Initial import: grid-bot — grid trading bot for BTC-USDT on Cifra Markets
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/Backtrace.h>
|
||||
#include <c10/util/env.h>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
|
||||
namespace c10 {
|
||||
class AbortHandlerHelper {
|
||||
public:
|
||||
static AbortHandlerHelper& getInstance() {
|
||||
#ifdef _WIN32
|
||||
thread_local
|
||||
#endif // _WIN32
|
||||
static AbortHandlerHelper instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void set(std::terminate_handler handler) {
|
||||
std::lock_guard<std::mutex> lk(mutex);
|
||||
if (!inited) {
|
||||
prev = std::set_terminate(handler);
|
||||
curr = std::get_terminate();
|
||||
inited = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::terminate_handler getPrev() const {
|
||||
return prev;
|
||||
}
|
||||
|
||||
private:
|
||||
std::terminate_handler prev = nullptr;
|
||||
std::terminate_handler curr = nullptr;
|
||||
bool inited = false;
|
||||
std::mutex mutex;
|
||||
AbortHandlerHelper() = default;
|
||||
~AbortHandlerHelper() {
|
||||
// Only restore the handler if we are the current one
|
||||
if (inited && curr == std::get_terminate()) {
|
||||
std::set_terminate(prev);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
AbortHandlerHelper(AbortHandlerHelper const&) = delete;
|
||||
void operator=(AbortHandlerHelper const&) = delete;
|
||||
AbortHandlerHelper(AbortHandlerHelper&&) = delete;
|
||||
void operator=(AbortHandlerHelper&&) = delete;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
C10_ALWAYS_INLINE void terminate_handler() {
|
||||
std::cout << "Unhandled exception caught in c10/util/AbortHandler.h" << '\n';
|
||||
auto backtrace = get_backtrace();
|
||||
std::cout << backtrace << '\n' << std::flush;
|
||||
auto prev_handler = AbortHandlerHelper::getInstance().getPrev();
|
||||
if (prev_handler) {
|
||||
prev_handler();
|
||||
} else {
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
C10_ALWAYS_INLINE void set_terminate_handler() {
|
||||
bool use_custom_terminate = false;
|
||||
// On Windows it is enabled by default based on
|
||||
// https://github.com/pytorch/pytorch/pull/50320#issuecomment-763147062
|
||||
#ifdef _WIN32
|
||||
use_custom_terminate = true;
|
||||
#endif // _WIN32
|
||||
auto result = c10::utils::check_env("TORCH_CUSTOM_TERMINATE");
|
||||
if (result != std::nullopt) {
|
||||
use_custom_terminate = result.value();
|
||||
}
|
||||
if (use_custom_terminate) {
|
||||
AbortHandlerHelper::getInstance().set(detail::terminate_handler);
|
||||
}
|
||||
}
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,181 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
//===--- AlignOf.h - Portable calculation of type alignment -----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file defines the AlignedCharArray and AlignedCharArrayUnion classes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// ATen: modified from llvm::AlignOf
|
||||
// replaced LLVM_ALIGNAS with alignas
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/// \struct AlignedCharArray
|
||||
/// \brief Helper for building an aligned character array type.
|
||||
///
|
||||
/// This template is used to explicitly build up a collection of aligned
|
||||
/// character array types. We have to build these up using a macro and explicit
|
||||
/// specialization to cope with MSVC (at least till 2015) where only an
|
||||
/// integer literal can be used to specify an alignment constraint. Once built
|
||||
/// up here, we can then begin to indirect between these using normal C++
|
||||
/// template parameters.
|
||||
|
||||
// MSVC requires special handling here.
|
||||
#ifndef _MSC_VER
|
||||
|
||||
template <size_t Alignment, size_t Size>
|
||||
struct AlignedCharArray {
|
||||
// NOLINTNEXTLINE(*c-arrays)
|
||||
alignas(Alignment) char buffer[Size];
|
||||
};
|
||||
|
||||
#else // _MSC_VER
|
||||
|
||||
/// \brief Create a type with an aligned char buffer.
|
||||
template <size_t Alignment, size_t Size>
|
||||
struct AlignedCharArray;
|
||||
|
||||
// We provide special variations of this template for the most common
|
||||
// alignments because __declspec(align(...)) doesn't actually work when it is
|
||||
// a member of a by-value function argument in MSVC, even if the alignment
|
||||
// request is something reasonably like 8-byte or 16-byte. Note that we can't
|
||||
// even include the declspec with the union that forces the alignment because
|
||||
// MSVC warns on the existence of the declspec despite the union member forcing
|
||||
// proper alignment.
|
||||
|
||||
template <size_t Size>
|
||||
struct AlignedCharArray<1, Size> {
|
||||
union {
|
||||
char aligned;
|
||||
char buffer[Size];
|
||||
};
|
||||
};
|
||||
|
||||
template <size_t Size>
|
||||
struct AlignedCharArray<2, Size> {
|
||||
union {
|
||||
short aligned;
|
||||
char buffer[Size];
|
||||
};
|
||||
};
|
||||
|
||||
template <size_t Size>
|
||||
struct AlignedCharArray<4, Size> {
|
||||
union {
|
||||
int aligned;
|
||||
char buffer[Size];
|
||||
};
|
||||
};
|
||||
|
||||
template <size_t Size>
|
||||
struct AlignedCharArray<8, Size> {
|
||||
union {
|
||||
double aligned;
|
||||
char buffer[Size];
|
||||
};
|
||||
};
|
||||
|
||||
// The rest of these are provided with a __declspec(align(...)) and we simply
|
||||
// can't pass them by-value as function arguments on MSVC.
|
||||
|
||||
#define AT_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \
|
||||
template <size_t Size> \
|
||||
struct AlignedCharArray<x, Size> { \
|
||||
__declspec(align(x)) char buffer[Size]; \
|
||||
};
|
||||
|
||||
AT_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16)
|
||||
AT_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32)
|
||||
AT_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64)
|
||||
AT_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128)
|
||||
|
||||
#undef AT_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT
|
||||
|
||||
#endif // _MSC_VER
|
||||
|
||||
namespace detail {
|
||||
template <
|
||||
typename T1,
|
||||
typename T2 = char,
|
||||
typename T3 = char,
|
||||
typename T4 = char,
|
||||
typename T5 = char,
|
||||
typename T6 = char,
|
||||
typename T7 = char,
|
||||
typename T8 = char,
|
||||
typename T9 = char,
|
||||
typename T10 = char>
|
||||
class AlignerImpl {
|
||||
T1 t1;
|
||||
T2 t2;
|
||||
T3 t3;
|
||||
T4 t4;
|
||||
T5 t5;
|
||||
T6 t6;
|
||||
T7 t7;
|
||||
T8 t8;
|
||||
T9 t9;
|
||||
T10 t10;
|
||||
|
||||
public:
|
||||
AlignerImpl() = delete;
|
||||
};
|
||||
|
||||
template <
|
||||
typename T1,
|
||||
typename T2 = char,
|
||||
typename T3 = char,
|
||||
typename T4 = char,
|
||||
typename T5 = char,
|
||||
typename T6 = char,
|
||||
typename T7 = char,
|
||||
typename T8 = char,
|
||||
typename T9 = char,
|
||||
typename T10 = char>
|
||||
union SizerImpl {
|
||||
// NOLINTNEXTLINE(*c-arrays)
|
||||
char arr1[sizeof(T1)], arr2[sizeof(T2)], arr3[sizeof(T3)], arr4[sizeof(T4)],
|
||||
arr5[sizeof(T5)], arr6[sizeof(T6)], arr7[sizeof(T7)], arr8[sizeof(T8)],
|
||||
arr9[sizeof(T9)], arr10[sizeof(T10)];
|
||||
};
|
||||
} // end namespace detail
|
||||
|
||||
/// \brief This union template exposes a suitably aligned and sized character
|
||||
/// array member which can hold elements of any of up to ten types.
|
||||
///
|
||||
/// These types may be arrays, structs, or any other types. The goal is to
|
||||
/// expose a char array buffer member which can be used as suitable storage for
|
||||
/// a placement new of any of these types. Support for more than ten types can
|
||||
/// be added at the cost of more boilerplate.
|
||||
template <
|
||||
typename T1,
|
||||
typename T2 = char,
|
||||
typename T3 = char,
|
||||
typename T4 = char,
|
||||
typename T5 = char,
|
||||
typename T6 = char,
|
||||
typename T7 = char,
|
||||
typename T8 = char,
|
||||
typename T9 = char,
|
||||
typename T10 = char>
|
||||
struct AlignedCharArrayUnion
|
||||
: AlignedCharArray<
|
||||
alignof(detail::AlignerImpl<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>),
|
||||
sizeof(::c10::detail::
|
||||
SizerImpl<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>)> {};
|
||||
} // end namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,132 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
// Copyright 2023-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Export.h>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
|
||||
#if defined(C10_IOS) && defined(C10_MOBILE)
|
||||
#include <sys/time.h> // for gettimeofday()
|
||||
#endif
|
||||
|
||||
#if defined(__i386__) || defined(__x86_64__) || defined(__amd64__)
|
||||
#define C10_RDTSC
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#elif defined(__CUDACC__) || defined(__HIPCC__)
|
||||
#undef C10_RDTSC
|
||||
#elif defined(__clang__)
|
||||
// `__rdtsc` is available by default.
|
||||
// NB: This has to be first, because Clang will also define `__GNUC__`
|
||||
#elif defined(__GNUC__)
|
||||
#include <x86intrin.h>
|
||||
#else
|
||||
#undef C10_RDTSC
|
||||
#endif
|
||||
#elif defined(__aarch64__) && !defined(__CUDACC__) && !defined(__HIPCC__)
|
||||
#define C10_ARMTSC
|
||||
#endif
|
||||
|
||||
namespace c10 {
|
||||
|
||||
using time_t = int64_t;
|
||||
using steady_clock_t = std::conditional_t<
|
||||
std::chrono::high_resolution_clock::is_steady,
|
||||
std::chrono::high_resolution_clock,
|
||||
std::chrono::steady_clock>;
|
||||
|
||||
inline time_t getTimeSinceEpoch() {
|
||||
auto now = std::chrono::system_clock::now().time_since_epoch();
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
|
||||
}
|
||||
|
||||
inline time_t getTime(bool allow_monotonic = false) {
|
||||
#if defined(C10_IOS) && defined(C10_MOBILE)
|
||||
// clock_gettime is only available on iOS 10.0 or newer. Unlike OS X, iOS
|
||||
// can't rely on CLOCK_REALTIME, as it is defined no matter if clock_gettime
|
||||
// is implemented or not
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
return static_cast<time_t>(now.tv_sec) * 1000000000 +
|
||||
static_cast<time_t>(now.tv_usec) * 1000;
|
||||
#elif defined(_WIN32) || defined(__MACH__)
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
steady_clock_t::now().time_since_epoch())
|
||||
.count();
|
||||
#else
|
||||
// clock_gettime is *much* faster than std::chrono implementation on Linux
|
||||
struct timespec t{};
|
||||
auto mode = CLOCK_REALTIME;
|
||||
if (allow_monotonic) {
|
||||
mode = CLOCK_MONOTONIC;
|
||||
}
|
||||
clock_gettime(mode, &t);
|
||||
return static_cast<time_t>(t.tv_sec) * 1000000000 +
|
||||
static_cast<time_t>(t.tv_nsec);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(C10_ARMTSC)
|
||||
inline uint64_t getArmApproximateTime() {
|
||||
uint64_t val;
|
||||
__asm__ __volatile__("mrs %0, cntvct_el0" : "=r"(val));
|
||||
return val;
|
||||
}
|
||||
#endif
|
||||
|
||||
// We often do not need to capture true wall times. If a fast mechanism such
|
||||
// as TSC is available we can use that instead and convert back to epoch time
|
||||
// during post processing. This greatly reduce the clock's contribution to
|
||||
// profiling.
|
||||
// http://btorpey.github.io/blog/2014/02/18/clock-sources-in-linux/
|
||||
// https://quick-bench.com/q/r8opkkGZSJMu9wM_XTbDouq-0Io
|
||||
// TODO: We should use
|
||||
// `https://github.com/google/benchmark/blob/main/src/cycleclock.h`
|
||||
inline auto getApproximateTime() {
|
||||
#if defined(C10_RDTSC)
|
||||
return static_cast<uint64_t>(__rdtsc());
|
||||
#elif defined(C10_ARMTSC)
|
||||
return getArmApproximateTime();
|
||||
#else
|
||||
return getTime();
|
||||
#endif
|
||||
}
|
||||
|
||||
using approx_time_t = decltype(getApproximateTime());
|
||||
static_assert(
|
||||
std::is_same_v<approx_time_t, int64_t> ||
|
||||
std::is_same_v<approx_time_t, uint64_t>,
|
||||
"Expected either int64_t (`getTime`) or uint64_t (some TSC reads).");
|
||||
|
||||
// Convert `getCount` results to Nanoseconds since unix epoch.
|
||||
class C10_API ApproximateClockToUnixTimeConverter final {
|
||||
public:
|
||||
ApproximateClockToUnixTimeConverter();
|
||||
std::function<time_t(approx_time_t)> makeConverter();
|
||||
|
||||
struct UnixAndApproximateTimePair {
|
||||
time_t t_;
|
||||
approx_time_t approx_t_;
|
||||
};
|
||||
static UnixAndApproximateTimePair measurePair();
|
||||
|
||||
private:
|
||||
static constexpr size_t replicates = 1001;
|
||||
using time_pairs = std::array<UnixAndApproximateTimePair, replicates>;
|
||||
time_pairs measurePairs();
|
||||
|
||||
time_pairs start_times_;
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,23 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// This helper function creates a constexpr std::array
|
||||
// From a compile time list of values, without requiring you to explicitly
|
||||
// write out the length.
|
||||
//
|
||||
// See also https://stackoverflow.com/a/26351760/23845
|
||||
template <typename V, typename... T>
|
||||
inline constexpr auto array_of(T&&... t) -> std::array<V, sizeof...(T)> {
|
||||
return {{std::forward<T>(t)...}};
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,326 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
//===--- ArrayRef.h - Array Reference Wrapper -------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// ATen: modified from llvm::ArrayRef.
|
||||
// removed llvm-specific functionality
|
||||
// removed some implicit const -> non-const conversions that rely on
|
||||
// complicated std::enable_if meta-programming
|
||||
// removed a bunch of slice variants for simplicity...
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/Exception.h>
|
||||
#include <c10/util/SmallVector.h>
|
||||
#include <torch/headeronly/util/HeaderOnlyArrayRef.h>
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <ostream>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace c10 {
|
||||
/// ArrayRef - Represent a constant reference to an array (0 or more elements
|
||||
/// consecutively in memory), i.e. a start pointer and a length. It allows
|
||||
/// various APIs to take consecutive elements easily and conveniently.
|
||||
///
|
||||
/// This class does not own the underlying data, it is expected to be used in
|
||||
/// situations where the data resides in some other buffer, whose lifetime
|
||||
/// extends past that of the ArrayRef. For this reason, it is not in general
|
||||
/// safe to store an ArrayRef.
|
||||
///
|
||||
/// This is intended to be trivially copyable, so it should be passed by
|
||||
/// value.
|
||||
///
|
||||
/// NOTE: We have refactored out the headeronly parts of the ArrayRef struct
|
||||
/// into HeaderOnlyArrayRef. As adding `virtual` would change the performance of
|
||||
/// the underlying constexpr calls, we rely on apparent-type dispatch for
|
||||
/// inheritance. This should be fine because their memory format is the same,
|
||||
/// and it is never incorrect for ArrayRef to call HeaderOnlyArrayRef methods.
|
||||
/// However, you should prefer to use ArrayRef when possible, because its use
|
||||
/// of TORCH_CHECK will lead to better user-facing error messages.
|
||||
template <typename T>
|
||||
// ArrayRef cannot be derived from. Normally, we would use `final`
|
||||
// specifier to force this constraint at compile time. However, Intel
|
||||
// compiler does not recognize ArrayRef as a class template (which is
|
||||
// required in the definition of at::TensorAccessor, for instance)
|
||||
// when `final` specifier is used. So, we cannot define ArrayRef as
|
||||
// final because of the Intel compiler issue.
|
||||
class ArrayRef : public HeaderOnlyArrayRef<T> {
|
||||
public:
|
||||
/// @name Constructors, all inherited from HeaderOnlyArrayRef except for
|
||||
/// SmallVector. As inherited constructors won't work with class template
|
||||
/// argument deduction (CTAD) until C++23, we add deduction guides after
|
||||
/// the class definition to enable CTAD.
|
||||
/// @{
|
||||
|
||||
using HeaderOnlyArrayRef<T>::HeaderOnlyArrayRef;
|
||||
|
||||
/// Construct an ArrayRef from a SmallVector. This is templated in order to
|
||||
/// avoid instantiating SmallVectorTemplateCommon<T> whenever we
|
||||
/// copy-construct an ArrayRef.
|
||||
/// NOTE: this is the only constructor that is not inherited from
|
||||
/// HeaderOnlyArrayRef.
|
||||
template <typename U>
|
||||
/* implicit */ ArrayRef(const SmallVectorTemplateCommon<T, U>& Vec)
|
||||
: HeaderOnlyArrayRef<T>(Vec.data(), Vec.size()) {}
|
||||
|
||||
/// @}
|
||||
/// @name Simple Operations, mostly inherited from HeaderOnlyArrayRef
|
||||
/// @{
|
||||
|
||||
/// front - Get the first element.
|
||||
/// We deviate from HeaderOnlyArrayRef by using TORCH_CHECK instead of
|
||||
/// STD_TORCH_CHECK
|
||||
constexpr const T& front() const {
|
||||
TORCH_CHECK(
|
||||
!this->empty(), "ArrayRef: attempted to access front() of empty list");
|
||||
return this->Data[0];
|
||||
}
|
||||
|
||||
/// back - Get the last element.
|
||||
/// We deviate from HeaderOnlyArrayRef by using TORCH_CHECK instead of
|
||||
/// STD_TORCH_CHECK
|
||||
constexpr const T& back() const {
|
||||
TORCH_CHECK(
|
||||
!this->empty(), "ArrayRef: attempted to access back() of empty list");
|
||||
return this->Data[this->Length - 1];
|
||||
}
|
||||
|
||||
/// slice(n, m) - Take M elements of the array starting at element N
|
||||
/// We deviate from HeaderOnlyArrayRef by using TORCH_CHECK instead of
|
||||
/// STD_TORCH_CHECK
|
||||
constexpr ArrayRef<T> slice(size_t N, size_t M) const {
|
||||
TORCH_CHECK(
|
||||
N + M <= this->size(),
|
||||
"ArrayRef: invalid slice, N = ",
|
||||
N,
|
||||
"; M = ",
|
||||
M,
|
||||
"; size = ",
|
||||
this->size());
|
||||
return ArrayRef<T>(this->data() + N, M);
|
||||
}
|
||||
|
||||
/// slice(n) - Chop off the first N elements of the array.
|
||||
/// We deviate from HeaderOnlyArrayRef by using TORCH_CHECK instead of
|
||||
/// STD_TORCH_CHECK
|
||||
constexpr ArrayRef<T> slice(size_t N) const {
|
||||
TORCH_CHECK(
|
||||
N <= this->size(),
|
||||
"ArrayRef: invalid slice, N = ",
|
||||
N,
|
||||
"; size = ",
|
||||
this->size());
|
||||
return slice(N, this->size() - N); // should this slice be this->slice?
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @name Operator Overloads
|
||||
/// @{
|
||||
|
||||
/// Vector compatibility
|
||||
/// We deviate from HeaderOnlyArrayRef by using TORCH_CHECK instead of
|
||||
/// STD_TORCH_CHECK
|
||||
constexpr const T& at(size_t Index) const {
|
||||
TORCH_CHECK(
|
||||
Index < this->Length,
|
||||
"ArrayRef: invalid index Index = ",
|
||||
Index,
|
||||
"; Length = ",
|
||||
this->Length);
|
||||
return this->Data[Index];
|
||||
}
|
||||
|
||||
/// Disallow accidental assignment from a temporary.
|
||||
///
|
||||
/// The declaration here is extra complicated so that "arrayRef = {}"
|
||||
/// continues to select the move assignment operator.
|
||||
template <typename U>
|
||||
std::enable_if_t<std::is_same_v<U, T>, ArrayRef<T>>& operator=(
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
|
||||
U&& Temporary) = delete;
|
||||
|
||||
/// Disallow accidental assignment from a temporary.
|
||||
///
|
||||
/// The declaration here is extra complicated so that "arrayRef = {}"
|
||||
/// continues to select the move assignment operator.
|
||||
template <typename U>
|
||||
std::enable_if_t<std::is_same_v<U, T>, ArrayRef<T>>& operator=(
|
||||
std::initializer_list<U>) = delete;
|
||||
|
||||
/// @}
|
||||
};
|
||||
|
||||
/// Deduction guides for ArrayRef to support CTAD with inherited constructors
|
||||
/// These mirror the constructors inherited from HeaderOnlyArrayRef
|
||||
/// @{
|
||||
|
||||
// Single element constructor
|
||||
template <typename T>
|
||||
ArrayRef(const T&) -> ArrayRef<T>;
|
||||
|
||||
// Pointer and length constructor
|
||||
template <typename T>
|
||||
ArrayRef(const T*, size_t) -> ArrayRef<T>;
|
||||
|
||||
// Range constructor (begin, end)
|
||||
template <typename T>
|
||||
ArrayRef(const T*, const T*) -> ArrayRef<T>;
|
||||
|
||||
// Generic container constructor (anything with .data() and .size())
|
||||
template <typename Container>
|
||||
ArrayRef(const Container&) -> ArrayRef<
|
||||
std::remove_pointer_t<decltype(std::declval<Container>().data())>>;
|
||||
|
||||
// std::vector constructor
|
||||
template <typename T, typename A>
|
||||
ArrayRef(const std::vector<T, A>&) -> ArrayRef<T>;
|
||||
|
||||
// std::array constructor
|
||||
template <typename T, size_t N>
|
||||
ArrayRef(const std::array<T, N>&) -> ArrayRef<T>;
|
||||
|
||||
// C array constructor
|
||||
template <typename T, size_t N>
|
||||
ArrayRef(const T (&)[N]) -> ArrayRef<T>;
|
||||
|
||||
// std::initializer_list constructor
|
||||
template <typename T>
|
||||
ArrayRef(const std::initializer_list<T>&) -> ArrayRef<T>;
|
||||
|
||||
/// @}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/// @name ArrayRef Convenience constructors
|
||||
/// @{
|
||||
|
||||
/// Construct an ArrayRef from a single element.
|
||||
template <typename T>
|
||||
ArrayRef<T> makeArrayRef(const T& OneElt) {
|
||||
return OneElt;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a pointer and length.
|
||||
template <typename T>
|
||||
ArrayRef<T> makeArrayRef(const T* data, size_t length) {
|
||||
return ArrayRef<T>(data, length);
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a range.
|
||||
template <typename T>
|
||||
ArrayRef<T> makeArrayRef(const T* begin, const T* end) {
|
||||
return ArrayRef<T>(begin, end);
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a SmallVector.
|
||||
template <typename T>
|
||||
ArrayRef<T> makeArrayRef(const SmallVectorImpl<T>& Vec) {
|
||||
return Vec;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a SmallVector.
|
||||
template <typename T, unsigned N>
|
||||
ArrayRef<T> makeArrayRef(const SmallVector<T, N>& Vec) {
|
||||
return Vec;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a std::vector.
|
||||
template <typename T>
|
||||
ArrayRef<T> makeArrayRef(const std::vector<T>& Vec) {
|
||||
return Vec;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a std::array.
|
||||
template <typename T, std::size_t N>
|
||||
ArrayRef<T> makeArrayRef(const std::array<T, N>& Arr) {
|
||||
return Arr;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from an ArrayRef (no-op) (const)
|
||||
template <typename T>
|
||||
ArrayRef<T> makeArrayRef(const ArrayRef<T>& Vec) {
|
||||
return Vec;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from an ArrayRef (no-op)
|
||||
template <typename T>
|
||||
ArrayRef<T>& makeArrayRef(ArrayRef<T>& Vec) {
|
||||
return Vec;
|
||||
}
|
||||
|
||||
/// Construct an ArrayRef from a C array.
|
||||
template <typename T, size_t N>
|
||||
// NOLINTNEXTLINE(*c-arrays*)
|
||||
ArrayRef<T> makeArrayRef(const T (&Arr)[N]) {
|
||||
return ArrayRef<T>(Arr);
|
||||
}
|
||||
|
||||
// WARNING: Template instantiation will NOT be willing to do an implicit
|
||||
// conversions to get you to an c10::ArrayRef, which is why we need so
|
||||
// many overloads.
|
||||
|
||||
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>;
|
||||
|
||||
using IntList [[deprecated(
|
||||
"This alias is deprecated because it doesn't make ownership semantics obvious. Use IntArrayRef instead!")]] =
|
||||
ArrayRef<int64_t>;
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/BFloat16.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,304 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/util/BFloat16.h>
|
||||
#include <c10/util/Half.h>
|
||||
|
||||
C10_CLANG_DIAGNOSTIC_PUSH()
|
||||
#if C10_CLANG_HAS_WARNING("-Wimplicit-float-conversion")
|
||||
C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-float-conversion")
|
||||
#endif
|
||||
|
||||
namespace c10 {
|
||||
template <typename T>
|
||||
struct is_reduced_floating_point
|
||||
: std::integral_constant<
|
||||
bool,
|
||||
std::is_same_v<T, c10::Half> || std::is_same_v<T, c10::BFloat16>> {};
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_reduced_floating_point_v =
|
||||
is_reduced_floating_point<T>::value;
|
||||
} // namespace c10
|
||||
|
||||
namespace std {
|
||||
|
||||
#if !defined(FBCODE_CAFFE2) && !defined(C10_NODEPRECATED)
|
||||
using c10::is_reduced_floating_point;
|
||||
using c10::is_reduced_floating_point_v;
|
||||
#endif // !defined(FBCODE_CAFFE2) && !defined(C10_NODEPRECATED)
|
||||
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T acos(T a) {
|
||||
return std::acos(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T asin(T a) {
|
||||
return std::asin(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T atan(T a) {
|
||||
return std::atan(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T atanh(T a) {
|
||||
return std::atanh(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T erf(T a) {
|
||||
return std::erf(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T erfc(T a) {
|
||||
return std::erfc(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T exp(T a) {
|
||||
return std::exp(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T expm1(T a) {
|
||||
return std::expm1(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline bool isfinite(T a) {
|
||||
return std::isfinite(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T log(T a) {
|
||||
return std::log(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T log10(T a) {
|
||||
return std::log10(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T log1p(T a) {
|
||||
return std::log1p(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T log2(T a) {
|
||||
return std::log2(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T ceil(T a) {
|
||||
return std::ceil(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T cos(T a) {
|
||||
return std::cos(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T floor(T a) {
|
||||
return std::floor(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T nearbyint(T a) {
|
||||
return std::nearbyint(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T sin(T a) {
|
||||
return std::sin(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T tan(T a) {
|
||||
return std::tan(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T sinh(T a) {
|
||||
return std::sinh(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T cosh(T a) {
|
||||
return std::cosh(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T tanh(T a) {
|
||||
return std::tanh(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T trunc(T a) {
|
||||
return std::trunc(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T lgamma(T a) {
|
||||
return std::lgamma(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T sqrt(T a) {
|
||||
return std::sqrt(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T rsqrt(T a) {
|
||||
return 1.0 / std::sqrt(float(a));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T abs(T a) {
|
||||
return std::abs(float(a));
|
||||
}
|
||||
#if defined(_MSC_VER) && defined(__CUDACC__)
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T pow(T a, double b) {
|
||||
return std::pow(float(a), float(b));
|
||||
}
|
||||
#else
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T pow(T a, double b) {
|
||||
return std::pow(float(a), b);
|
||||
}
|
||||
#endif
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T pow(T a, T b) {
|
||||
return std::pow(float(a), float(b));
|
||||
}
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
inline T fmod(T a, T b) {
|
||||
return std::fmod(float(a), float(b));
|
||||
}
|
||||
|
||||
/*
|
||||
The following function is inspired from the implementation in `musl`
|
||||
Link to License: https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT
|
||||
----------------------------------------------------------------------
|
||||
Copyright © 2005-2020 Rich Felker, et al.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
template <
|
||||
typename T,
|
||||
typename std::enable_if_t<c10::is_reduced_floating_point_v<T>, int> = 0>
|
||||
C10_HOST_DEVICE inline T nextafter(T from, T to) {
|
||||
// Reference:
|
||||
// https://git.musl-libc.org/cgit/musl/tree/src/math/nextafter.c
|
||||
using int_repr_t = uint16_t;
|
||||
constexpr uint8_t bits = 16;
|
||||
union {
|
||||
T f;
|
||||
int_repr_t i;
|
||||
} ufrom = {from}, uto = {to};
|
||||
|
||||
// get a mask to get the sign bit i.e. MSB
|
||||
int_repr_t sign_mask = int_repr_t{1} << (bits - 1);
|
||||
|
||||
// short-circuit: if either is NaN, return NaN
|
||||
if (from != from || to != to) {
|
||||
return from + to;
|
||||
}
|
||||
|
||||
// short-circuit: if they are exactly the same.
|
||||
if (ufrom.i == uto.i) {
|
||||
return from;
|
||||
}
|
||||
|
||||
// mask the sign-bit to zero i.e. positive
|
||||
// equivalent to abs(x)
|
||||
int_repr_t abs_from = ufrom.i & ~sign_mask;
|
||||
int_repr_t abs_to = uto.i & ~sign_mask;
|
||||
if (abs_from == 0) {
|
||||
// if both are zero but with different sign,
|
||||
// preserve the sign of `to`.
|
||||
if (abs_to == 0) {
|
||||
return to;
|
||||
}
|
||||
// smallest subnormal with sign of `to`.
|
||||
ufrom.i = (uto.i & sign_mask) | int_repr_t{1};
|
||||
return ufrom.f;
|
||||
}
|
||||
|
||||
// if abs(from) > abs(to) or sign(from) != sign(to)
|
||||
if (abs_from > abs_to || ((ufrom.i ^ uto.i) & sign_mask)) {
|
||||
ufrom.i--;
|
||||
} else {
|
||||
ufrom.i++;
|
||||
}
|
||||
|
||||
return ufrom.f;
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
C10_CLANG_DIAGNOSTIC_POP()
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/BFloat16.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,36 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#ifndef C10_UTIL_BACKTRACE_H_
|
||||
#define C10_UTIL_BACKTRACE_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/Lazy.h>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// Symbolizing the backtrace can be expensive; pass it around as a lazy string
|
||||
// so it is symbolized only if actually needed.
|
||||
using Backtrace = std::shared_ptr<const LazyValue<std::string>>;
|
||||
|
||||
// DEPRECATED: Prefer get_lazy_backtrace().
|
||||
C10_API std::string get_backtrace(
|
||||
size_t frames_to_skip = 0,
|
||||
size_t maximum_number_of_frames = 64,
|
||||
bool skip_python_frames = true);
|
||||
|
||||
C10_API Backtrace get_lazy_backtrace(
|
||||
size_t frames_to_skip = 0,
|
||||
size_t maximum_number_of_frames = 64,
|
||||
bool skip_python_frames = true);
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#endif // C10_UTIL_BACKTRACE_H_
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,123 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace c10::utils {
|
||||
|
||||
/**
|
||||
* This is a simple bitset class with sizeof(long long int) bits.
|
||||
* You can set bits, unset bits, query bits by index,
|
||||
* and query for the first set bit.
|
||||
* Before using this class, please also take a look at std::bitset,
|
||||
* which has more functionality and is more generic. It is probably
|
||||
* a better fit for your use case. The sole reason for c10::utils::bitset
|
||||
* to exist is that std::bitset misses a find_first_set() method.
|
||||
*/
|
||||
struct bitset final {
|
||||
private:
|
||||
#if defined(_MSC_VER)
|
||||
// MSVCs _BitScanForward64 expects int64_t
|
||||
using bitset_type = int64_t;
|
||||
#else
|
||||
// POSIX ffsll expects long long int
|
||||
using bitset_type = long long int;
|
||||
#endif
|
||||
public:
|
||||
static constexpr size_t NUM_BITS() {
|
||||
return 8 * sizeof(bitset_type);
|
||||
}
|
||||
|
||||
constexpr bitset() noexcept = default;
|
||||
constexpr bitset(const bitset&) noexcept = default;
|
||||
constexpr bitset(bitset&&) noexcept = default;
|
||||
// there is an issue for gcc 5.3.0 when define default function as constexpr
|
||||
// see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68754.
|
||||
bitset& operator=(const bitset&) noexcept = default;
|
||||
bitset& operator=(bitset&&) noexcept = default;
|
||||
~bitset() = default;
|
||||
|
||||
constexpr void set(size_t index) noexcept {
|
||||
bitset_ |= (static_cast<long long int>(1) << index);
|
||||
}
|
||||
|
||||
constexpr void unset(size_t index) noexcept {
|
||||
bitset_ &= ~(static_cast<long long int>(1) << index);
|
||||
}
|
||||
|
||||
constexpr bool get(size_t index) const noexcept {
|
||||
return bitset_ & (static_cast<long long int>(1) << index);
|
||||
}
|
||||
|
||||
constexpr bool is_entirely_unset() const noexcept {
|
||||
return 0 == bitset_;
|
||||
}
|
||||
|
||||
// Call the given functor with the index of each bit that is set
|
||||
template <class Func>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
|
||||
void for_each_set_bit(Func&& func) const {
|
||||
bitset cur = *this;
|
||||
size_t index = cur.find_first_set();
|
||||
while (0 != index) {
|
||||
// -1 because find_first_set() is not one-indexed.
|
||||
index -= 1;
|
||||
func(index);
|
||||
cur.unset(index);
|
||||
index = cur.find_first_set();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Return the index of the first set bit. The returned index is one-indexed
|
||||
// (i.e. if the very first bit is set, this function returns '1'), and a
|
||||
// return of '0' means that there was no bit set.
|
||||
size_t find_first_set() const {
|
||||
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64))
|
||||
unsigned long result;
|
||||
bool has_bits_set = (0 != _BitScanForward64(&result, bitset_));
|
||||
if (!has_bits_set) {
|
||||
return 0;
|
||||
}
|
||||
return result + 1;
|
||||
#elif defined(_MSC_VER) && defined(_M_IX86)
|
||||
unsigned long result;
|
||||
if (static_cast<uint32_t>(bitset_) != 0) {
|
||||
bool has_bits_set =
|
||||
(0 != _BitScanForward(&result, static_cast<uint32_t>(bitset_)));
|
||||
if (!has_bits_set) {
|
||||
return 0;
|
||||
}
|
||||
return result + 1;
|
||||
} else {
|
||||
bool has_bits_set =
|
||||
(0 != _BitScanForward(&result, static_cast<uint32_t>(bitset_ >> 32)));
|
||||
if (!has_bits_set) {
|
||||
return 32;
|
||||
}
|
||||
return result + 33;
|
||||
}
|
||||
#else
|
||||
return __builtin_ffsll(bitset_);
|
||||
#endif
|
||||
}
|
||||
|
||||
friend bool operator==(bitset lhs, bitset rhs) noexcept {
|
||||
return lhs.bitset_ == rhs.bitset_;
|
||||
}
|
||||
|
||||
bitset_type bitset_{0};
|
||||
};
|
||||
|
||||
inline bool operator!=(bitset lhs, bitset rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
} // namespace c10::utils
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,43 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
#ifndef C10_UTIL_CPP17_H_
|
||||
#define C10_UTIL_CPP17_H_
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
|
||||
namespace c10::guts {
|
||||
|
||||
#if defined(__HIP__)
|
||||
|
||||
// std::apply is not available in HIP device code because it lacks
|
||||
// __host__ __device__ annotations in the standard library.
|
||||
namespace detail {
|
||||
template <class F, class Tuple, std::size_t... INDEX>
|
||||
C10_HOST_DEVICE constexpr auto apply_impl(
|
||||
F&& f,
|
||||
Tuple&& t,
|
||||
std::index_sequence<INDEX...>) {
|
||||
return std::forward<F>(f)(std::get<INDEX>(std::forward<Tuple>(t))...);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <class F, class Tuple>
|
||||
C10_HOST_DEVICE constexpr auto apply(F&& f, Tuple&& t) {
|
||||
return detail::apply_impl(
|
||||
std::forward<F>(f),
|
||||
std::forward<Tuple>(t),
|
||||
std::make_index_sequence<
|
||||
std::tuple_size<std::remove_reference_t<Tuple>>::value>{});
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace c10::guts
|
||||
|
||||
#endif // C10_UTIL_CPP17_H_
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,74 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// custom c10 call_once implementation to avoid the deadlock in std::call_once.
|
||||
// The implementation here is a simplified version from folly and likely much
|
||||
// much higher memory footprint.
|
||||
template <typename Flag, typename F, typename... Args>
|
||||
inline void call_once(Flag& flag, F&& f, Args&&... args) {
|
||||
if (C10_LIKELY(flag.test_once())) {
|
||||
return;
|
||||
}
|
||||
flag.call_once_slow(std::forward<F>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
class once_flag {
|
||||
public:
|
||||
#ifndef _WIN32
|
||||
// running into build error on MSVC. Can't seem to get a repro locally so I'm
|
||||
// just avoiding constexpr
|
||||
//
|
||||
// C:/actions-runner/_work/pytorch/pytorch\c10/util/CallOnce.h(26): error:
|
||||
// defaulted default constructor cannot be constexpr because the
|
||||
// corresponding implicitly declared default constructor would not be
|
||||
// constexpr 1 error detected in the compilation of
|
||||
// "C:/actions-runner/_work/pytorch/pytorch/aten/src/ATen/cuda/cub.cu".
|
||||
constexpr
|
||||
#endif
|
||||
once_flag() noexcept = default;
|
||||
once_flag(const once_flag&) = delete;
|
||||
once_flag& operator=(const once_flag&) = delete;
|
||||
once_flag(once_flag&&) = delete;
|
||||
once_flag& operator=(once_flag&&) = delete;
|
||||
~once_flag() = default;
|
||||
bool test_once() {
|
||||
return init_.load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Flag, typename F, typename... Args>
|
||||
friend void call_once(Flag& flag, F&& f, Args&&... args);
|
||||
|
||||
template <typename F, typename... Args>
|
||||
void call_once_slow(F&& f, Args&&... args) {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
if (init_.load(std::memory_order_relaxed)) {
|
||||
return;
|
||||
}
|
||||
std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
|
||||
init_.store(true, std::memory_order_release);
|
||||
}
|
||||
|
||||
void reset_once() {
|
||||
init_.store(false, std::memory_order_release);
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::atomic<bool> init_{false};
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,137 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/IdWrapper.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
|
||||
namespace c10::util {
|
||||
|
||||
namespace detail {
|
||||
// NOLINTNEXTLINE(*c-arrays*)
|
||||
constexpr uint64_t crc64_table[] = {
|
||||
0x0000000000000000, 0x7ad870c830358979, 0xf5b0e190606b12f2,
|
||||
0x8f689158505e9b8b, 0xc038e5739841b68f, 0xbae095bba8743ff6,
|
||||
0x358804e3f82aa47d, 0x4f50742bc81f2d04, 0xab28ecb46814fe75,
|
||||
0xd1f09c7c5821770c, 0x5e980d24087fec87, 0x24407dec384a65fe,
|
||||
0x6b1009c7f05548fa, 0x11c8790fc060c183, 0x9ea0e857903e5a08,
|
||||
0xe478989fa00bd371, 0x7d08ff3b88be6f81, 0x07d08ff3b88be6f8,
|
||||
0x88b81eabe8d57d73, 0xf2606e63d8e0f40a, 0xbd301a4810ffd90e,
|
||||
0xc7e86a8020ca5077, 0x4880fbd87094cbfc, 0x32588b1040a14285,
|
||||
0xd620138fe0aa91f4, 0xacf86347d09f188d, 0x2390f21f80c18306,
|
||||
0x594882d7b0f40a7f, 0x1618f6fc78eb277b, 0x6cc0863448deae02,
|
||||
0xe3a8176c18803589, 0x997067a428b5bcf0, 0xfa11fe77117cdf02,
|
||||
0x80c98ebf2149567b, 0x0fa11fe77117cdf0, 0x75796f2f41224489,
|
||||
0x3a291b04893d698d, 0x40f16bccb908e0f4, 0xcf99fa94e9567b7f,
|
||||
0xb5418a5cd963f206, 0x513912c379682177, 0x2be1620b495da80e,
|
||||
0xa489f35319033385, 0xde51839b2936bafc, 0x9101f7b0e12997f8,
|
||||
0xebd98778d11c1e81, 0x64b116208142850a, 0x1e6966e8b1770c73,
|
||||
0x8719014c99c2b083, 0xfdc17184a9f739fa, 0x72a9e0dcf9a9a271,
|
||||
0x08719014c99c2b08, 0x4721e43f0183060c, 0x3df994f731b68f75,
|
||||
0xb29105af61e814fe, 0xc849756751dd9d87, 0x2c31edf8f1d64ef6,
|
||||
0x56e99d30c1e3c78f, 0xd9810c6891bd5c04, 0xa3597ca0a188d57d,
|
||||
0xec09088b6997f879, 0x96d1784359a27100, 0x19b9e91b09fcea8b,
|
||||
0x636199d339c963f2, 0xdf7adabd7a6e2d6f, 0xa5a2aa754a5ba416,
|
||||
0x2aca3b2d1a053f9d, 0x50124be52a30b6e4, 0x1f423fcee22f9be0,
|
||||
0x659a4f06d21a1299, 0xeaf2de5e82448912, 0x902aae96b271006b,
|
||||
0x74523609127ad31a, 0x0e8a46c1224f5a63, 0x81e2d7997211c1e8,
|
||||
0xfb3aa75142244891, 0xb46ad37a8a3b6595, 0xceb2a3b2ba0eecec,
|
||||
0x41da32eaea507767, 0x3b024222da65fe1e, 0xa2722586f2d042ee,
|
||||
0xd8aa554ec2e5cb97, 0x57c2c41692bb501c, 0x2d1ab4dea28ed965,
|
||||
0x624ac0f56a91f461, 0x1892b03d5aa47d18, 0x97fa21650afae693,
|
||||
0xed2251ad3acf6fea, 0x095ac9329ac4bc9b, 0x7382b9faaaf135e2,
|
||||
0xfcea28a2faafae69, 0x8632586aca9a2710, 0xc9622c4102850a14,
|
||||
0xb3ba5c8932b0836d, 0x3cd2cdd162ee18e6, 0x460abd1952db919f,
|
||||
0x256b24ca6b12f26d, 0x5fb354025b277b14, 0xd0dbc55a0b79e09f,
|
||||
0xaa03b5923b4c69e6, 0xe553c1b9f35344e2, 0x9f8bb171c366cd9b,
|
||||
0x10e3202993385610, 0x6a3b50e1a30ddf69, 0x8e43c87e03060c18,
|
||||
0xf49bb8b633338561, 0x7bf329ee636d1eea, 0x012b592653589793,
|
||||
0x4e7b2d0d9b47ba97, 0x34a35dc5ab7233ee, 0xbbcbcc9dfb2ca865,
|
||||
0xc113bc55cb19211c, 0x5863dbf1e3ac9dec, 0x22bbab39d3991495,
|
||||
0xadd33a6183c78f1e, 0xd70b4aa9b3f20667, 0x985b3e827bed2b63,
|
||||
0xe2834e4a4bd8a21a, 0x6debdf121b863991, 0x1733afda2bb3b0e8,
|
||||
0xf34b37458bb86399, 0x8993478dbb8deae0, 0x06fbd6d5ebd3716b,
|
||||
0x7c23a61ddbe6f812, 0x3373d23613f9d516, 0x49aba2fe23cc5c6f,
|
||||
0xc6c333a67392c7e4, 0xbc1b436e43a74e9d, 0x95ac9329ac4bc9b5,
|
||||
0xef74e3e19c7e40cc, 0x601c72b9cc20db47, 0x1ac40271fc15523e,
|
||||
0x5594765a340a7f3a, 0x2f4c0692043ff643, 0xa02497ca54616dc8,
|
||||
0xdafce7026454e4b1, 0x3e847f9dc45f37c0, 0x445c0f55f46abeb9,
|
||||
0xcb349e0da4342532, 0xb1eceec59401ac4b, 0xfebc9aee5c1e814f,
|
||||
0x8464ea266c2b0836, 0x0b0c7b7e3c7593bd, 0x71d40bb60c401ac4,
|
||||
0xe8a46c1224f5a634, 0x927c1cda14c02f4d, 0x1d148d82449eb4c6,
|
||||
0x67ccfd4a74ab3dbf, 0x289c8961bcb410bb, 0x5244f9a98c8199c2,
|
||||
0xdd2c68f1dcdf0249, 0xa7f41839ecea8b30, 0x438c80a64ce15841,
|
||||
0x3954f06e7cd4d138, 0xb63c61362c8a4ab3, 0xcce411fe1cbfc3ca,
|
||||
0x83b465d5d4a0eece, 0xf96c151de49567b7, 0x76048445b4cbfc3c,
|
||||
0x0cdcf48d84fe7545, 0x6fbd6d5ebd3716b7, 0x15651d968d029fce,
|
||||
0x9a0d8ccedd5c0445, 0xe0d5fc06ed698d3c, 0xaf85882d2576a038,
|
||||
0xd55df8e515432941, 0x5a3569bd451db2ca, 0x20ed197575283bb3,
|
||||
0xc49581ead523e8c2, 0xbe4df122e51661bb, 0x3125607ab548fa30,
|
||||
0x4bfd10b2857d7349, 0x04ad64994d625e4d, 0x7e7514517d57d734,
|
||||
0xf11d85092d094cbf, 0x8bc5f5c11d3cc5c6, 0x12b5926535897936,
|
||||
0x686de2ad05bcf04f, 0xe70573f555e26bc4, 0x9ddd033d65d7e2bd,
|
||||
0xd28d7716adc8cfb9, 0xa85507de9dfd46c0, 0x273d9686cda3dd4b,
|
||||
0x5de5e64efd965432, 0xb99d7ed15d9d8743, 0xc3450e196da80e3a,
|
||||
0x4c2d9f413df695b1, 0x36f5ef890dc31cc8, 0x79a59ba2c5dc31cc,
|
||||
0x037deb6af5e9b8b5, 0x8c157a32a5b7233e, 0xf6cd0afa9582aa47,
|
||||
0x4ad64994d625e4da, 0x300e395ce6106da3, 0xbf66a804b64ef628,
|
||||
0xc5bed8cc867b7f51, 0x8aeeace74e645255, 0xf036dc2f7e51db2c,
|
||||
0x7f5e4d772e0f40a7, 0x05863dbf1e3ac9de, 0xe1fea520be311aaf,
|
||||
0x9b26d5e88e0493d6, 0x144e44b0de5a085d, 0x6e963478ee6f8124,
|
||||
0x21c640532670ac20, 0x5b1e309b16452559, 0xd476a1c3461bbed2,
|
||||
0xaeaed10b762e37ab, 0x37deb6af5e9b8b5b, 0x4d06c6676eae0222,
|
||||
0xc26e573f3ef099a9, 0xb8b627f70ec510d0, 0xf7e653dcc6da3dd4,
|
||||
0x8d3e2314f6efb4ad, 0x0256b24ca6b12f26, 0x788ec2849684a65f,
|
||||
0x9cf65a1b368f752e, 0xe62e2ad306bafc57, 0x6946bb8b56e467dc,
|
||||
0x139ecb4366d1eea5, 0x5ccebf68aecec3a1, 0x2616cfa09efb4ad8,
|
||||
0xa97e5ef8cea5d153, 0xd3a62e30fe90582a, 0xb0c7b7e3c7593bd8,
|
||||
0xca1fc72bf76cb2a1, 0x45775673a732292a, 0x3faf26bb9707a053,
|
||||
0x70ff52905f188d57, 0x0a2722586f2d042e, 0x854fb3003f739fa5,
|
||||
0xff97c3c80f4616dc, 0x1bef5b57af4dc5ad, 0x61372b9f9f784cd4,
|
||||
0xee5fbac7cf26d75f, 0x9487ca0fff135e26, 0xdbd7be24370c7322,
|
||||
0xa10fceec0739fa5b, 0x2e675fb4576761d0, 0x54bf2f7c6752e8a9,
|
||||
0xcdcf48d84fe75459, 0xb71738107fd2dd20, 0x387fa9482f8c46ab,
|
||||
0x42a7d9801fb9cfd2, 0x0df7adabd7a6e2d6, 0x772fdd63e7936baf,
|
||||
0xf8474c3bb7cdf024, 0x829f3cf387f8795d, 0x66e7a46c27f3aa2c,
|
||||
0x1c3fd4a417c62355, 0x935745fc4798b8de, 0xe98f353477ad31a7,
|
||||
0xa6df411fbfb21ca3, 0xdc0731d78f8795da, 0x536fa08fdfd90e51,
|
||||
0x29b7d047efec8728,
|
||||
};
|
||||
|
||||
inline constexpr uint64_t crc64impl(
|
||||
uint64_t accumulator,
|
||||
const char* data,
|
||||
size_t size) {
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
accumulator =
|
||||
crc64_table[(accumulator ^ data[i]) & 0xFF] ^ (accumulator >> 8);
|
||||
}
|
||||
return accumulator;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
struct crc64_t final : IdWrapper<crc64_t, uint64_t> {
|
||||
constexpr crc64_t(uint64_t checksum) : IdWrapper(checksum) {}
|
||||
constexpr uint64_t checksum() const {
|
||||
return this->underlyingId();
|
||||
}
|
||||
};
|
||||
|
||||
// CRC64 with Jones coefficients and an init value of 0.
|
||||
inline constexpr crc64_t crc64(const char* str, size_t size) {
|
||||
return crc64_t{detail::crc64impl(0, str, size)};
|
||||
}
|
||||
|
||||
inline constexpr crc64_t crc64(std::string_view str) {
|
||||
return crc64(str.data(), str.size());
|
||||
}
|
||||
} // namespace c10::util
|
||||
|
||||
// Allow usage of crc64_t in std::unordered_set
|
||||
C10_DEFINE_HASH_FOR_IDWRAPPER(c10::util::crc64_t)
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,57 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Export.h>
|
||||
#include <c10/util/Exception.h>
|
||||
|
||||
/// This file provides some simple utilities for detecting common deadlocks in
|
||||
/// PyTorch. For now, we focus exclusively on detecting Python GIL deadlocks,
|
||||
/// as the GIL is a wide ranging lock that is taken out in many situations.
|
||||
/// The basic strategy is before performing an operation that may block, you
|
||||
/// can use TORCH_ASSERT_NO_GIL_WITHOUT_PYTHON_DEP() to assert that the GIL is
|
||||
/// not held. This macro is to be used in contexts where no static dependency
|
||||
/// on Python is available (we will handle indirecting a virtual call for you).
|
||||
///
|
||||
/// If the GIL is held by a torchdeploy interpreter, we always report false.
|
||||
/// If you are in a context where Python bindings are available, it's better
|
||||
/// to directly assert on PyGILState_Check (as it avoids a vcall and also
|
||||
/// works correctly with torchdeploy.)
|
||||
|
||||
#define TORCH_ASSERT_NO_GIL_WITHOUT_PYTHON_DEP() \
|
||||
TORCH_INTERNAL_ASSERT( \
|
||||
!c10::impl::check_python_gil(), \
|
||||
"Holding GIL before a blocking operation! Please release the GIL before blocking, or see https://github.com/pytorch/pytorch/issues/56297 for how to release the GIL for destructors of objects")
|
||||
|
||||
namespace c10::impl {
|
||||
|
||||
C10_API bool check_python_gil();
|
||||
|
||||
struct C10_API PythonGILHooks {
|
||||
virtual ~PythonGILHooks() = default;
|
||||
// Returns true if we hold the GIL. If not linked against Python we
|
||||
// always return false.
|
||||
virtual bool check_python_gil() const = 0;
|
||||
};
|
||||
|
||||
C10_API void SetPythonGILHooks(PythonGILHooks* factory);
|
||||
|
||||
// DO NOT call this registerer from a torch deploy instance! You will clobber
|
||||
// other registrations
|
||||
struct C10_API PythonGILHooksRegisterer {
|
||||
explicit PythonGILHooksRegisterer(PythonGILHooks* factory) {
|
||||
SetPythonGILHooks(factory);
|
||||
}
|
||||
PythonGILHooksRegisterer(const PythonGILHooksRegisterer&) = delete;
|
||||
PythonGILHooksRegisterer(PythonGILHooksRegisterer&&) = delete;
|
||||
PythonGILHooksRegisterer& operator=(const PythonGILHooksRegisterer&) = delete;
|
||||
PythonGILHooksRegisterer& operator=(PythonGILHooksRegisterer&&) = delete;
|
||||
~PythonGILHooksRegisterer() {
|
||||
SetPythonGILHooks(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace c10::impl
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,7 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
#include <torch/headeronly/util/Deprecated.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,22 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/core/SymInt.h>
|
||||
#include <c10/core/impl/SizesAndStrides.h>
|
||||
#include <c10/util/SmallVector.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
constexpr size_t kDimVectorStaticSize = C10_SIZES_AND_STRIDES_MAX_INLINE_SIZE;
|
||||
|
||||
/// A container for sizes or strides
|
||||
using DimVector = SmallVector<int64_t, kDimVectorStaticSize>;
|
||||
using SymDimVector = SmallVector<c10::SymInt, kDimVectorStaticSize>;
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,54 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
|
||||
namespace c10::monitor {
|
||||
|
||||
class C10_API DynamicCounter {
|
||||
public:
|
||||
using Callback = std::function<int64_t()>;
|
||||
|
||||
// Creates a dynamic counter that can be queried at any point in time by
|
||||
// multiple backends. Only one counter with a given key can exist at any point
|
||||
// in time.
|
||||
//
|
||||
// The callback is invoked every time the counter is queried.
|
||||
// The callback must be thread-safe.
|
||||
// The callback must not throw.
|
||||
// The callback must not block.
|
||||
DynamicCounter(std::string_view key, Callback getCounterCallback);
|
||||
|
||||
// Unregisters the callback.
|
||||
// Waits for all ongoing callback invocations to finish.
|
||||
~DynamicCounter();
|
||||
|
||||
private:
|
||||
struct Guard;
|
||||
std::unique_ptr<Guard> guard_;
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
class DynamicCounterBackendIf {
|
||||
public:
|
||||
virtual ~DynamicCounterBackendIf() = default;
|
||||
|
||||
virtual void registerCounter(
|
||||
std::string_view key,
|
||||
DynamicCounter::Callback getCounterCallback) = 0;
|
||||
// MUST wait for all ongoing callback invocations to finish
|
||||
virtual void unregisterCounter(std::string_view key) = 0;
|
||||
};
|
||||
|
||||
void C10_API registerDynamicCounterBackend(
|
||||
std::unique_ptr<DynamicCounterBackendIf> /*backend*/);
|
||||
} // namespace detail
|
||||
} // namespace c10::monitor
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,164 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
/*
|
||||
* Ported from folly/container/Enumerate.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <basetsd.h> // @manual
|
||||
using ssize_t = SSIZE_T;
|
||||
#endif
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
|
||||
/**
|
||||
* Similar to Python's enumerate(), enumerate() can be used to
|
||||
* iterate a range with a for-range loop, and it also allows to
|
||||
* retrieve the count of iterations so far. Can be used in constexpr
|
||||
* context.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* for (auto&& [index, element] : enumerate(vec)) {
|
||||
* // index is a const reference to a size_t containing the iteration count.
|
||||
* // element is a reference to the type contained within vec, mutable
|
||||
* // unless vec is const.
|
||||
* }
|
||||
*
|
||||
* If the binding is const, the element reference is too.
|
||||
*
|
||||
* for (const auto&& [index, element] : enumerate(vec)) {
|
||||
* // element is always a const reference.
|
||||
* }
|
||||
*
|
||||
* It can also be used as follows:
|
||||
*
|
||||
* for (auto&& it : enumerate(vec)) {
|
||||
* // *it is a reference to the current element. Mutable unless vec is const.
|
||||
* // it->member can be used as well.
|
||||
* // it.index contains the iteration count.
|
||||
* }
|
||||
*
|
||||
* As before, const auto&& it can also be used.
|
||||
*/
|
||||
|
||||
namespace c10 {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <class T>
|
||||
struct MakeConst {
|
||||
using type = const T;
|
||||
};
|
||||
template <class T>
|
||||
struct MakeConst<T&> {
|
||||
using type = const T&;
|
||||
};
|
||||
template <class T>
|
||||
struct MakeConst<T*> {
|
||||
using type = const T*;
|
||||
};
|
||||
|
||||
template <class Iterator>
|
||||
class Enumerator {
|
||||
public:
|
||||
constexpr explicit Enumerator(Iterator it) : it_(std::move(it)) {}
|
||||
|
||||
class Proxy {
|
||||
public:
|
||||
using difference_type = ssize_t;
|
||||
using value_type = typename std::iterator_traits<Iterator>::value_type;
|
||||
using reference = typename std::iterator_traits<Iterator>::reference;
|
||||
using pointer = typename std::iterator_traits<Iterator>::pointer;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
C10_ALWAYS_INLINE constexpr explicit Proxy(const Enumerator& e)
|
||||
: index(e.idx_), element(*e.it_) {}
|
||||
|
||||
// Non-const Proxy: Forward constness from Iterator.
|
||||
C10_ALWAYS_INLINE constexpr reference operator*() {
|
||||
return element;
|
||||
}
|
||||
C10_ALWAYS_INLINE constexpr pointer operator->() {
|
||||
return std::addressof(element);
|
||||
}
|
||||
|
||||
// Const Proxy: Force const references.
|
||||
C10_ALWAYS_INLINE constexpr typename MakeConst<reference>::type operator*()
|
||||
const {
|
||||
return element;
|
||||
}
|
||||
C10_ALWAYS_INLINE constexpr typename MakeConst<pointer>::type operator->()
|
||||
const {
|
||||
return std::addressof(element);
|
||||
}
|
||||
|
||||
public:
|
||||
size_t index;
|
||||
reference element;
|
||||
};
|
||||
|
||||
C10_ALWAYS_INLINE constexpr Proxy operator*() const {
|
||||
return Proxy(*this);
|
||||
}
|
||||
|
||||
C10_ALWAYS_INLINE constexpr Enumerator& operator++() {
|
||||
++it_;
|
||||
++idx_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename OtherIterator>
|
||||
C10_ALWAYS_INLINE constexpr bool operator==(
|
||||
const Enumerator<OtherIterator>& rhs) const {
|
||||
return it_ == rhs.it_;
|
||||
}
|
||||
|
||||
template <typename OtherIterator>
|
||||
C10_ALWAYS_INLINE constexpr bool operator!=(
|
||||
const Enumerator<OtherIterator>& rhs) const {
|
||||
return !(it_ == rhs.it_);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename OtherIterator>
|
||||
friend class Enumerator;
|
||||
|
||||
Iterator it_;
|
||||
size_t idx_ = 0;
|
||||
};
|
||||
|
||||
template <class Range>
|
||||
class RangeEnumerator {
|
||||
Range r_;
|
||||
using BeginIteratorType = decltype(std::declval<Range>().begin());
|
||||
using EndIteratorType = decltype(std::declval<Range>().end());
|
||||
|
||||
public:
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-rvalue-reference-param-not-moved)
|
||||
constexpr explicit RangeEnumerator(Range&& r) : r_(std::forward<Range>(r)) {}
|
||||
|
||||
constexpr Enumerator<BeginIteratorType> begin() {
|
||||
return Enumerator<BeginIteratorType>(r_.begin());
|
||||
}
|
||||
constexpr Enumerator<EndIteratorType> end() {
|
||||
return Enumerator<EndIteratorType>(r_.end());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class Range>
|
||||
constexpr detail::RangeEnumerator<Range> enumerate(Range&& r) {
|
||||
return detail::RangeEnumerator<Range>(std::forward<Range>(r));
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,880 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
// @allow-raw-throw
|
||||
#ifndef C10_UTIL_EXCEPTION_H_
|
||||
#define C10_UTIL_EXCEPTION_H_
|
||||
|
||||
#include <c10/macros/Export.h>
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/Backtrace.h>
|
||||
#include <c10/util/Lazy.h>
|
||||
#include <c10/util/StringUtil.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1900
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/// The primary ATen error class.
|
||||
/// Provides a complete error message with source location information via
|
||||
/// `what()`, and a more concise message via `what_without_backtrace()`.
|
||||
/// Don't throw this directly; use TORCH_CHECK/TORCH_INTERNAL_ASSERT instead.
|
||||
///
|
||||
/// NB: c10::Error is handled specially by the default torch to suppress the
|
||||
/// backtrace, see torch/csrc/Exceptions.h
|
||||
class C10_API Error : public std::exception {
|
||||
private:
|
||||
// The actual error message.
|
||||
std::string msg_;
|
||||
|
||||
// Context for the message (in order of decreasing specificity). Context will
|
||||
// be automatically formatted appropriately, so it is not necessary to add
|
||||
// extra leading/trailing newlines to strings inside this vector
|
||||
std::vector<std::string> context_;
|
||||
|
||||
// The C++ backtrace at the point when this exception was raised. This
|
||||
// may be empty if there is no valid backtrace. (We don't use optional
|
||||
// here to reduce the dependencies this file has.)
|
||||
Backtrace backtrace_;
|
||||
|
||||
// These two are derived fields from msg_stack_ and backtrace_, but we need
|
||||
// fields for the strings so that we can return a const char* (as the
|
||||
// signature of std::exception requires). Currently, the invariant
|
||||
// is that these fields are ALWAYS populated consistently with respect
|
||||
// to msg_stack_ and backtrace_.
|
||||
mutable OptimisticLazy<std::string> what_;
|
||||
std::string what_without_backtrace_;
|
||||
|
||||
// This is a little debugging trick: you can stash a relevant pointer
|
||||
// in caller, and then when you catch the exception, you can compare
|
||||
// against pointers you have on hand to get more information about
|
||||
// where the exception came from. In Caffe2, this is used to figure
|
||||
// out which operator raised an exception.
|
||||
const void* caller_;
|
||||
|
||||
public:
|
||||
// PyTorch-style Error constructor. NB: the implementation of this
|
||||
// is actually in Logging.cpp
|
||||
Error(SourceLocation source_location, std::string msg);
|
||||
|
||||
// Caffe2-style error message
|
||||
Error(
|
||||
const char* file,
|
||||
const uint32_t line,
|
||||
const char* condition,
|
||||
const std::string& msg,
|
||||
Backtrace backtrace,
|
||||
const void* caller = nullptr);
|
||||
|
||||
// Base constructor
|
||||
Error(
|
||||
std::string msg,
|
||||
Backtrace backtrace = nullptr,
|
||||
const void* caller = nullptr);
|
||||
|
||||
// Add some new context to the message stack. The last added context
|
||||
// will be formatted at the end of the context list upon printing.
|
||||
// WARNING: This method is O(n) in the size of the stack, so don't go
|
||||
// wild adding a ridiculous amount of context to error messages.
|
||||
void add_context(std::string msg);
|
||||
|
||||
const std::string& msg() const {
|
||||
return msg_;
|
||||
}
|
||||
|
||||
const std::vector<std::string>& context() const {
|
||||
return context_;
|
||||
}
|
||||
|
||||
const Backtrace& backtrace() const;
|
||||
|
||||
/// Returns the complete error message, including the source location.
|
||||
/// The returned pointer is invalidated if you call add_context() on
|
||||
/// this object.
|
||||
const char* what() const noexcept override;
|
||||
|
||||
const void* caller() const noexcept {
|
||||
return caller_;
|
||||
}
|
||||
|
||||
/// Returns only the error message string, without source location.
|
||||
/// The returned pointer is invalidated if you call add_context() on
|
||||
/// this object.
|
||||
virtual const char* what_without_backtrace() const noexcept {
|
||||
return what_without_backtrace_.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
void refresh_what();
|
||||
std::string compute_what(bool include_backtrace) const;
|
||||
};
|
||||
|
||||
class C10_API Warning {
|
||||
public:
|
||||
class C10_API UserWarning{};
|
||||
class C10_API DeprecationWarning{};
|
||||
|
||||
using warning_variant_t = std::variant<UserWarning, DeprecationWarning>;
|
||||
|
||||
Warning(
|
||||
warning_variant_t type,
|
||||
const SourceLocation& source_location,
|
||||
std::string msg,
|
||||
bool verbatim);
|
||||
|
||||
Warning(
|
||||
warning_variant_t type,
|
||||
SourceLocation source_location,
|
||||
const char* msg,
|
||||
bool verbatim);
|
||||
|
||||
Warning(
|
||||
warning_variant_t type,
|
||||
SourceLocation source_location,
|
||||
::c10::detail::CompileTimeEmptyString msg,
|
||||
bool verbatim);
|
||||
|
||||
// Getters for members
|
||||
warning_variant_t type() const;
|
||||
const SourceLocation& source_location() const;
|
||||
const std::string& msg() const;
|
||||
bool verbatim() const;
|
||||
|
||||
private:
|
||||
// The type of warning
|
||||
warning_variant_t type_;
|
||||
|
||||
// Where the warning happened.
|
||||
SourceLocation source_location_;
|
||||
|
||||
// The actual warning message.
|
||||
std::string msg_;
|
||||
|
||||
// See note: [Verbatim Warnings]
|
||||
bool verbatim_;
|
||||
};
|
||||
|
||||
using UserWarning = Warning::UserWarning;
|
||||
using DeprecationWarning = Warning::DeprecationWarning;
|
||||
|
||||
// Issue a warning with a given message. Dispatched to the current
|
||||
// warning handler.
|
||||
void C10_API warn(const Warning& warning);
|
||||
|
||||
class C10_API WarningHandler {
|
||||
public:
|
||||
virtual ~WarningHandler() = default;
|
||||
/// The default warning handler. Prints the message to stderr.
|
||||
virtual void process(const Warning& warning);
|
||||
};
|
||||
|
||||
namespace WarningUtils {
|
||||
|
||||
// Note: [Verbatim Warnings]
|
||||
// Warnings originating in C++ code can appear out-of-place to Python users:
|
||||
// a user runs a line in Python, but the warning references a line in C++.
|
||||
// Some parts of PyTorch, like the JIT, are cognizant of this mismatch
|
||||
// and take care to map warnings back to the user's program, but most
|
||||
// of PyTorch simply throws a context-free warning. To allow warning
|
||||
// handlers to add context where appropriate, warn takes the
|
||||
// "verbatim" flag. When this is false a warning handler might append
|
||||
// the C++ warning to a Python warning message that relates the warning
|
||||
// back to the user's program. Callers who have already accounted for
|
||||
// context in their warnings should set verbatim to true so their warnings
|
||||
// appear without modification.
|
||||
|
||||
/// Sets the global warning handler. This is not thread-safe, so it should
|
||||
/// generally be called once during initialization or while holding the GIL
|
||||
/// for programs that use python.
|
||||
/// User is responsible for keeping the WarningHandler alive until
|
||||
/// it is not needed.
|
||||
C10_API void set_warning_handler(WarningHandler* handler) noexcept(true);
|
||||
/// Gets the global warning handler.
|
||||
C10_API WarningHandler* get_warning_handler() noexcept(true);
|
||||
|
||||
class C10_API WarningHandlerGuard {
|
||||
WarningHandler* prev_handler_;
|
||||
|
||||
public:
|
||||
WarningHandlerGuard(WarningHandler* new_handler)
|
||||
: prev_handler_(c10::WarningUtils::get_warning_handler()) {
|
||||
c10::WarningUtils::set_warning_handler(new_handler);
|
||||
}
|
||||
WarningHandlerGuard(WarningHandlerGuard&& other) = delete;
|
||||
WarningHandlerGuard(const WarningHandlerGuard&) = delete;
|
||||
WarningHandlerGuard& operator=(const WarningHandlerGuard&) = delete;
|
||||
WarningHandlerGuard& operator=(WarningHandlerGuard&&) = delete;
|
||||
~WarningHandlerGuard() {
|
||||
c10::WarningUtils::set_warning_handler(prev_handler_);
|
||||
}
|
||||
};
|
||||
|
||||
/// The TORCH_WARN_ONCE macro is difficult to test for. Use
|
||||
/// setWarnAlways(true) to turn it into TORCH_WARN, which can be
|
||||
/// tested for more easily.
|
||||
C10_API void set_warnAlways(bool /*setting*/) noexcept(true);
|
||||
C10_API bool get_warnAlways() noexcept(true);
|
||||
|
||||
// A RAII guard that sets warn_always (not thread-local) on
|
||||
// construction, and sets it back to the original value upon destruction.
|
||||
struct C10_API WarnAlways {
|
||||
public:
|
||||
explicit WarnAlways(bool setting = true);
|
||||
~WarnAlways();
|
||||
|
||||
private:
|
||||
bool prev_setting;
|
||||
};
|
||||
|
||||
} // namespace WarningUtils
|
||||
|
||||
// Like Error, but we always report the C++ backtrace, instead of only
|
||||
// reporting when TORCH_SHOW_CPP_STACKTRACES
|
||||
class C10_API ErrorAlwaysShowCppStacktrace : public Error {
|
||||
using Error::Error;
|
||||
const char* what_without_backtrace() const noexcept override {
|
||||
return what();
|
||||
}
|
||||
};
|
||||
|
||||
// Used in ATen for out-of-bound indices that can reasonably only be detected
|
||||
// lazily inside a kernel (See: advanced indexing). These turn into
|
||||
// IndexError when they cross to Python.
|
||||
class C10_API IndexError : public Error {
|
||||
using Error::Error;
|
||||
};
|
||||
|
||||
// Used in ATen for invalid values. These turn into
|
||||
// ValueError when they cross to Python.
|
||||
class C10_API ValueError : public Error {
|
||||
using Error::Error;
|
||||
};
|
||||
|
||||
// Used in ATen for invalid types. These turn into
|
||||
// TypeError when they cross to Python.
|
||||
class C10_API TypeError : public Error {
|
||||
using Error::Error;
|
||||
};
|
||||
|
||||
// Used in ATen for functionality that is not implemented. These turn into
|
||||
// NotImplementedError when they cross to Python.
|
||||
class C10_API NotImplementedError : public Error {
|
||||
using Error::Error;
|
||||
};
|
||||
|
||||
// Used in ATen for buffer-related errors, e.g. trying to create a DLPack of
|
||||
// an unsupported device. These turn into BufferError when they cross to
|
||||
// Python.
|
||||
class C10_API BufferError : public Error {
|
||||
using Error::Error;
|
||||
};
|
||||
|
||||
// Used in ATen for non finite indices. These turn into
|
||||
// ExitException when they cross to Python.
|
||||
class C10_API EnforceFiniteError : public Error {
|
||||
using Error::Error;
|
||||
};
|
||||
|
||||
// Used in Onnxifi backend lowering. These turn into
|
||||
// ExitException when they cross to Python.
|
||||
class C10_API OnnxfiBackendSystemError : public Error {
|
||||
using Error::Error;
|
||||
};
|
||||
|
||||
// Used for numerical errors from the linalg module. These
|
||||
// turn into LinAlgError when they cross into Python.
|
||||
class C10_API LinAlgError : public Error {
|
||||
using Error::Error;
|
||||
};
|
||||
|
||||
class C10_API OutOfMemoryError : public Error {
|
||||
using Error::Error;
|
||||
};
|
||||
|
||||
// Used for handling syntactic errors in input arguments.
|
||||
// These turn into SyntaxError when the cross into Python.
|
||||
class C10_API SyntaxError : public Error {
|
||||
using Error::Error;
|
||||
};
|
||||
|
||||
// Raised when accelerator API call hits an error.
|
||||
// These turn into AcceleratorError when the cross into Python
|
||||
class C10_API AcceleratorError : public Error {
|
||||
int32_t error_code;
|
||||
|
||||
public:
|
||||
AcceleratorError(SourceLocation loc, int32_t code, const std::string& msg)
|
||||
: Error(loc, msg), error_code(code) {}
|
||||
int32_t get_error_code() const {
|
||||
return error_code;
|
||||
}
|
||||
};
|
||||
|
||||
// Base error type for all distributed errors.
|
||||
// These turn into DistError when they cross into Python.
|
||||
class C10_API DistError : public Error {
|
||||
using Error::Error;
|
||||
};
|
||||
|
||||
// Used for collective communication library errors from the distributed module.
|
||||
// These turn into DistBackendError when they cross into Python.
|
||||
class C10_API DistBackendError : public DistError {
|
||||
using DistError::DistError;
|
||||
};
|
||||
|
||||
// Used for errors originating from the store.
|
||||
// These turn into DistStoreError when they cross into Python.
|
||||
class C10_API DistStoreError : public DistError {
|
||||
using DistError::DistError;
|
||||
};
|
||||
|
||||
// Used for errors originating from the TCP/IP stack and not from collective
|
||||
// libraries. These turn into DistNetworkError when they cross into Python.
|
||||
class C10_API DistNetworkError : public DistError {
|
||||
using DistError::DistError;
|
||||
};
|
||||
|
||||
// Raised when a queue is empty and a non-blocking pop is called.
|
||||
// Translated to torch.distributed.QueueEmptyError in Python
|
||||
class C10_API DistQueueEmptyError : public DistStoreError {
|
||||
using DistStoreError::DistStoreError;
|
||||
};
|
||||
|
||||
// A utility function to return an exception std::string by prepending its
|
||||
// exception type before its what() content
|
||||
C10_API std::string GetExceptionString(const std::exception& e);
|
||||
|
||||
} // namespace c10
|
||||
|
||||
// Private helper macro for implementing TORCH_INTERNAL_ASSERT and TORCH_CHECK
|
||||
//
|
||||
// Note: In the debug build With MSVC, __LINE__ might be of long type (a.k.a
|
||||
// int32_t), which is different from the definition of `SourceLocation` that
|
||||
// requires unsigned int (a.k.a uint32_t) and may cause a compile error with the
|
||||
// message: error C2397: conversion from 'long' to 'uint32_t' requires a
|
||||
// narrowing conversion Here the static cast is used to pass the build. if this
|
||||
// is used inside a lambda the __func__ macro expands to operator(), which isn't
|
||||
// very useful, but hard to fix in a macro so suppressing the warning.
|
||||
#define C10_THROW_ERROR(err_type, msg) \
|
||||
throw ::c10::err_type( \
|
||||
{__func__, __FILE__, static_cast<uint32_t>(__LINE__)}, msg)
|
||||
|
||||
#define C10_BUILD_ERROR(err_type, msg) \
|
||||
::c10::err_type({__func__, __FILE__, static_cast<uint32_t>(__LINE__)}, msg)
|
||||
|
||||
// Private helper macro for workaround MSVC misexpansion of nested macro
|
||||
// invocations involving __VA_ARGS__. See
|
||||
// https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
|
||||
#define C10_EXPAND_MSVC_WORKAROUND(x) x
|
||||
|
||||
#include <torch/headeronly/util/Exception.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Error reporting macros
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifdef STRIP_ERROR_MESSAGES
|
||||
#define TORCH_RETHROW(e, ...) \
|
||||
do { \
|
||||
(void)e; /* Suppress unused variable warning */ \
|
||||
throw; \
|
||||
} while (false)
|
||||
#else
|
||||
#define TORCH_RETHROW(e, ...) \
|
||||
do { \
|
||||
e.add_context(::c10::str(__VA_ARGS__)); \
|
||||
throw; \
|
||||
} while (false)
|
||||
#endif
|
||||
|
||||
// A utility macro to provide assert()-like functionality; that is, enforcement
|
||||
// of internal invariants in code. It supports an arbitrary number of extra
|
||||
// arguments (evaluated only on failure), which will be printed in the assert
|
||||
// failure message using operator<< (this is useful to print some variables
|
||||
// which may be useful for debugging.)
|
||||
//
|
||||
// Usage:
|
||||
// TORCH_INTERNAL_ASSERT(should_be_true);
|
||||
// TORCH_INTERNAL_ASSERT(x == 0, "x = ", x);
|
||||
//
|
||||
// Assuming no bugs in PyTorch, the conditions tested by this macro should
|
||||
// always be true; e.g., it should be possible to disable all of these
|
||||
// conditions without changing observable user behavior. If you would like to
|
||||
// do error reporting for user input, please use TORCH_CHECK instead.
|
||||
//
|
||||
// NOTE: It is SAFE to use this macro in production code; on failure, this
|
||||
// simply raises an exception, it does NOT unceremoniously quit the process
|
||||
// (unlike assert()).
|
||||
//
|
||||
#ifdef STRIP_ERROR_MESSAGES
|
||||
#define TORCH_INTERNAL_ASSERT(cond, ...) \
|
||||
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
|
||||
::c10::detail::torchCheckFail( \
|
||||
__func__, \
|
||||
__FILE__, \
|
||||
static_cast<uint32_t>(__LINE__), \
|
||||
#cond " INTERNAL ASSERT FAILED at " C10_STRINGIZE(__FILE__)); \
|
||||
}
|
||||
#else
|
||||
// It would be nice if we could build a combined string literal out of
|
||||
// the TORCH_INTERNAL_ASSERT prefix and a user-provided string literal
|
||||
// as the first argument, but there doesn't seem to be any good way to
|
||||
// do that while still supporting having a first argument that isn't a
|
||||
// string literal.
|
||||
#define TORCH_INTERNAL_ASSERT(cond, ...) \
|
||||
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
|
||||
::c10::detail::torchInternalAssertFail( \
|
||||
__func__, \
|
||||
__FILE__, \
|
||||
static_cast<uint32_t>(__LINE__), \
|
||||
#cond \
|
||||
" INTERNAL ASSERT FAILED at " C10_STRINGIZE(__FILE__) ":" C10_STRINGIZE( \
|
||||
__LINE__) ", please report a bug to PyTorch. ", \
|
||||
c10::str(__VA_ARGS__)); \
|
||||
}
|
||||
#endif
|
||||
|
||||
// A utility macro to make it easier to test for error conditions from user
|
||||
// input. Like TORCH_INTERNAL_ASSERT, it supports an arbitrary number of extra
|
||||
// arguments (evaluated only on failure), which will be printed in the error
|
||||
// message using operator<< (e.g., you can pass any object which has
|
||||
// operator<< defined. Most objects in PyTorch have these definitions!)
|
||||
//
|
||||
// Usage:
|
||||
// TORCH_CHECK(should_be_true); // A default error message will be provided
|
||||
// // in this case; but we recommend writing an
|
||||
// // explicit error message, as it is more
|
||||
// // user friendly.
|
||||
// TORCH_CHECK(x == 0, "Expected x to be 0, but got ", x);
|
||||
//
|
||||
// On failure, this macro will raise an exception. If this exception propagates
|
||||
// to Python, it will convert into a Python RuntimeError.
|
||||
//
|
||||
// NOTE: It is SAFE to use this macro in production code; on failure, this
|
||||
// simply raises an exception, it does NOT unceremoniously quit the process
|
||||
// (unlike CHECK() from glog.)
|
||||
//
|
||||
#define TORCH_CHECK_WITH(error_t, cond, ...) \
|
||||
TORCH_CHECK_WITH_MSG(error_t, cond, "", __VA_ARGS__)
|
||||
|
||||
#ifdef STRIP_ERROR_MESSAGES
|
||||
#define TORCH_CHECK_MSG(cond, type, ...) \
|
||||
(#cond #type " CHECK FAILED at " C10_STRINGIZE(__FILE__))
|
||||
#define TORCH_CHECK_WITH_MSG(error_t, cond, type, ...) \
|
||||
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
|
||||
C10_THROW_ERROR(Error, TORCH_CHECK_MSG(cond, type, __VA_ARGS__)); \
|
||||
}
|
||||
#else
|
||||
|
||||
namespace c10::detail {
|
||||
template <typename... Args>
|
||||
auto torchCheckMsgImpl(const char* /*msg*/, const Args&... args) {
|
||||
return ::c10::str(args...);
|
||||
}
|
||||
inline C10_API const char* torchCheckMsgImpl(const char* msg) {
|
||||
return msg;
|
||||
}
|
||||
// If there is just 1 user-provided C-string argument, use it.
|
||||
inline C10_API const char* torchCheckMsgImpl(
|
||||
const char* /*msg*/,
|
||||
const char* args) {
|
||||
return args;
|
||||
}
|
||||
} // namespace c10::detail
|
||||
|
||||
#define TORCH_CHECK_MSG(cond, type, ...) \
|
||||
(::c10::detail::torchCheckMsgImpl( \
|
||||
"Expected " #cond \
|
||||
" to be true, but got false. " \
|
||||
"(Could this error message be improved? If so, " \
|
||||
"please report an enhancement request to PyTorch.)", \
|
||||
##__VA_ARGS__))
|
||||
#define TORCH_CHECK_WITH_MSG(error_t, cond, type, ...) \
|
||||
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
|
||||
C10_THROW_ERROR(error_t, TORCH_CHECK_MSG(cond, type, __VA_ARGS__)); \
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace c10::detail {
|
||||
|
||||
[[noreturn]] C10_API void torchCheckFail(
|
||||
const char* func,
|
||||
const char* file,
|
||||
uint32_t line,
|
||||
const std::string& msg);
|
||||
[[noreturn]] C10_API void torchCheckFail(
|
||||
const char* func,
|
||||
const char* file,
|
||||
uint32_t line,
|
||||
const char* msg);
|
||||
|
||||
// The c10::str() call that creates userMsg can have 1 of 3 return
|
||||
// types depending on the number and types of arguments passed to
|
||||
// TORCH_INTERNAL_ASSERT. 0 arguments will get a
|
||||
// CompileTimeEmptyString, 1 const char * will be passed straight
|
||||
// through, and anything else will get converted to std::string.
|
||||
[[noreturn]] C10_API void torchInternalAssertFail(
|
||||
const char* func,
|
||||
const char* file,
|
||||
uint32_t line,
|
||||
const char* condMsg,
|
||||
const char* userMsg);
|
||||
[[noreturn]] inline C10_API void torchInternalAssertFail(
|
||||
const char* func,
|
||||
const char* file,
|
||||
uint32_t line,
|
||||
const char* condMsg,
|
||||
::c10::detail::CompileTimeEmptyString /*userMsg*/) {
|
||||
torchCheckFail(func, file, line, condMsg);
|
||||
}
|
||||
[[noreturn]] C10_API void torchInternalAssertFail(
|
||||
const char* func,
|
||||
const char* file,
|
||||
uint32_t line,
|
||||
const char* condMsg,
|
||||
const std::string& userMsg);
|
||||
|
||||
} // namespace c10::detail
|
||||
|
||||
#ifdef STANDALONE_TORCH_HEADER
|
||||
|
||||
// TORCH_CHECK throws std::runtime_error instead of c10::Error which is
|
||||
// useful when certain headers are used in a libtorch-independent way,
|
||||
// e.g. when Vectorized<T> is used in AOTInductor generated code.
|
||||
#ifdef STRIP_ERROR_MESSAGES
|
||||
#define TORCH_CHECK(cond, ...) \
|
||||
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
|
||||
throw std::runtime_error(TORCH_CHECK_MSG( \
|
||||
cond, \
|
||||
"", \
|
||||
__func__, \
|
||||
", ", \
|
||||
__FILE__, \
|
||||
":", \
|
||||
__LINE__, \
|
||||
", ", \
|
||||
__VA_ARGS__)); \
|
||||
}
|
||||
#else
|
||||
#define TORCH_CHECK(cond, ...) \
|
||||
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
|
||||
throw std::runtime_error(TORCH_CHECK_MSG( \
|
||||
cond, \
|
||||
"", \
|
||||
__func__, \
|
||||
", ", \
|
||||
__FILE__, \
|
||||
":", \
|
||||
__LINE__, \
|
||||
", ", \
|
||||
##__VA_ARGS__)); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#ifdef STRIP_ERROR_MESSAGES
|
||||
#define TORCH_CHECK(cond, ...) \
|
||||
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
|
||||
::c10::detail::torchCheckFail( \
|
||||
__func__, \
|
||||
__FILE__, \
|
||||
static_cast<uint32_t>(__LINE__), \
|
||||
TORCH_CHECK_MSG(cond, "", __VA_ARGS__)); \
|
||||
}
|
||||
#else
|
||||
#define TORCH_CHECK(cond, ...) \
|
||||
if (C10_UNLIKELY_OR_CONST(!(cond))) { \
|
||||
::c10::detail::torchCheckFail( \
|
||||
__func__, \
|
||||
__FILE__, \
|
||||
static_cast<uint32_t>(__LINE__), \
|
||||
TORCH_CHECK_MSG(cond, "", ##__VA_ARGS__)); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// An utility macro that does what `TORCH_CHECK` does if compiled in the host
|
||||
// code, otherwise does nothing. Supposed to be used in the code shared between
|
||||
// host and device code as an alternative for `TORCH_CHECK`.
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
#define TORCH_CHECK_IF_NOT_ON_CUDA(cond, ...)
|
||||
#else
|
||||
#define TORCH_CHECK_IF_NOT_ON_CUDA(cond, ...) TORCH_CHECK(cond, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
// Debug only version of TORCH_INTERNAL_ASSERT. This macro only checks in debug
|
||||
// build, and does nothing in release build. It is appropriate to use
|
||||
// in situations where you want to add an assert to a hotpath, but it is
|
||||
// too expensive to run this assert on production builds.
|
||||
#ifdef NDEBUG
|
||||
// Optimized version - generates no code.
|
||||
#define TORCH_INTERNAL_ASSERT_DEBUG_ONLY(...) \
|
||||
while (false) \
|
||||
C10_EXPAND_MSVC_WORKAROUND(TORCH_INTERNAL_ASSERT(__VA_ARGS__))
|
||||
#else
|
||||
#define TORCH_INTERNAL_ASSERT_DEBUG_ONLY(...) \
|
||||
C10_EXPAND_MSVC_WORKAROUND(TORCH_INTERNAL_ASSERT(__VA_ARGS__))
|
||||
#endif
|
||||
|
||||
// TODO: We're going to get a lot of similar looking string literals
|
||||
// this way; check if this actually affects binary size.
|
||||
|
||||
// Like TORCH_CHECK, but raises LinAlgError instead of Error.
|
||||
#define TORCH_CHECK_LINALG(cond, ...) \
|
||||
TORCH_CHECK_WITH_MSG(LinAlgError, cond, "LINALG", __VA_ARGS__)
|
||||
|
||||
// Like TORCH_CHECK, but raises IndexErrors instead of Errors.
|
||||
#define TORCH_CHECK_INDEX(cond, ...) \
|
||||
TORCH_CHECK_WITH_MSG(IndexError, cond, "INDEX", __VA_ARGS__)
|
||||
|
||||
// Like TORCH_CHECK, but raises ValueErrors instead of Errors.
|
||||
#define TORCH_CHECK_VALUE(cond, ...) \
|
||||
TORCH_CHECK_WITH_MSG(ValueError, cond, "VALUE", __VA_ARGS__)
|
||||
|
||||
// Like TORCH_CHECK, but raises TypeErrors instead of Errors.
|
||||
#define TORCH_CHECK_TYPE(cond, ...) \
|
||||
TORCH_CHECK_WITH_MSG(TypeError, cond, "TYPE", __VA_ARGS__)
|
||||
|
||||
// Like TORCH_CHECK, but raises NotImplementedErrors instead of Errors.
|
||||
#define TORCH_CHECK_NOT_IMPLEMENTED(cond, ...) \
|
||||
TORCH_CHECK_WITH_MSG(NotImplementedError, cond, "TYPE", __VA_ARGS__)
|
||||
|
||||
// Like TORCH_CHECK, but raises BufferError instead of Errors.
|
||||
#define TORCH_CHECK_BUFFER(cond, ...) \
|
||||
TORCH_CHECK_WITH_MSG(BufferError, cond, "TYPE", __VA_ARGS__)
|
||||
|
||||
#define TORCH_CHECK_ALWAYS_SHOW_CPP_STACKTRACE(cond, ...) \
|
||||
TORCH_CHECK_WITH_MSG( \
|
||||
ErrorAlwaysShowCppStacktrace, cond, "TYPE", ##__VA_ARGS__)
|
||||
|
||||
#ifdef STRIP_ERROR_MESSAGES
|
||||
#define WARNING_MESSAGE_STRING(...) \
|
||||
::c10::detail::CompileTimeEmptyString {}
|
||||
#else
|
||||
#define WARNING_MESSAGE_STRING(...) ::c10::str(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
// Report a warning to the user. Accepts an arbitrary number of extra
|
||||
// arguments which are concatenated into the warning message using operator<<
|
||||
//
|
||||
#ifdef DISABLE_WARN
|
||||
#define _TORCH_WARN_WITH(...) ((void)0);
|
||||
#else
|
||||
#define _TORCH_WARN_WITH(warning_t, ...) \
|
||||
::c10::warn(::c10::Warning( \
|
||||
warning_t(), \
|
||||
{__func__, __FILE__, static_cast<uint32_t>(__LINE__)}, \
|
||||
WARNING_MESSAGE_STRING(__VA_ARGS__), \
|
||||
false));
|
||||
#endif
|
||||
|
||||
#define TORCH_WARN(...) _TORCH_WARN_WITH(::c10::UserWarning, __VA_ARGS__);
|
||||
|
||||
#define TORCH_WARN_DEPRECATION(...) \
|
||||
_TORCH_WARN_WITH(::c10::DeprecationWarning, __VA_ARGS__);
|
||||
|
||||
// Report a warning to the user only once. Accepts an arbitrary number of extra
|
||||
// arguments which are concatenated into the warning message using operator<<
|
||||
//
|
||||
#define _TORCH_WARN_ONCE(...) \
|
||||
[[maybe_unused]] static const auto C10_ANONYMOUS_VARIABLE( \
|
||||
torch_warn_once_) = [&] { \
|
||||
TORCH_WARN(__VA_ARGS__); \
|
||||
return true; \
|
||||
}()
|
||||
|
||||
#ifdef DISABLE_WARN
|
||||
#define TORCH_WARN_ONCE(...) ((void)0);
|
||||
#else
|
||||
#define TORCH_WARN_ONCE(...) \
|
||||
if (::c10::WarningUtils::get_warnAlways()) { \
|
||||
TORCH_WARN(__VA_ARGS__); \
|
||||
} else { \
|
||||
_TORCH_WARN_ONCE(__VA_ARGS__); \
|
||||
}
|
||||
#endif
|
||||
|
||||
// Report an error with a specific argument
|
||||
// NOTE: using the argument name in TORCH_CHECK's message is preferred
|
||||
#define TORCH_CHECK_ARG(cond, argN, ...) \
|
||||
TORCH_CHECK(cond, "invalid argument ", argN, ": ", __VA_ARGS__)
|
||||
|
||||
#ifndef FATAL_IF
|
||||
#ifdef C10_USE_GLOG
|
||||
#define FATAL_IF(condition) \
|
||||
condition ? (void)0 \
|
||||
: ::c10::LoggerVoidify() & \
|
||||
::c10::MessageLogger( \
|
||||
::c10::SourceLocation::current(), ::google::GLOG_FATAL) \
|
||||
.stream()
|
||||
#else
|
||||
#define FATAL_IF(condition) \
|
||||
condition ? (void)0 \
|
||||
: ::c10::LoggerVoidify() & \
|
||||
::c10::MessageLogger( \
|
||||
::c10::SourceLocation::current(), ::c10::GLOG_FATAL) \
|
||||
.stream()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef NON_FATAL_IF
|
||||
#ifdef C10_USE_GLOG
|
||||
#define NON_FATAL_IF(condition) \
|
||||
condition ? (void)0 \
|
||||
: ::c10::LoggerVoidify() & \
|
||||
::c10::MessageLogger( \
|
||||
::c10::SourceLocation::current(), ::google::GLOG_FATAL, false) \
|
||||
.stream()
|
||||
#else
|
||||
#define NON_FATAL_IF(condition) \
|
||||
condition ? (void)0 \
|
||||
: ::c10::LoggerVoidify() & \
|
||||
::c10::MessageLogger( \
|
||||
::c10::SourceLocation::current(), ::c10::GLOG_FATAL, false) \
|
||||
.stream()
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Binary comparison check macros
|
||||
#define TORCH_CHECK_OP(val1, val2, op) \
|
||||
NON_FATAL_IF(((val1)op(val2))) \
|
||||
<< "Check failed: " #val1 " " #op " " #val2 " (" << (val1) << " vs. " \
|
||||
<< (val2) << "). "
|
||||
|
||||
#define TORCH_DCHECK_OP(val1, val2, op) \
|
||||
FATAL_IF(((val1)op(val2))) << "Check failed: " #val1 " " #op " " #val2 " (" \
|
||||
<< (val1) << " vs. " << (val2) << "). "
|
||||
|
||||
#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, >)
|
||||
|
||||
// Debug versions of TORCH_CHECK_OP macros
|
||||
#ifndef NDEBUG
|
||||
#define TORCH_DCHECK_EQ(val1, val2) TORCH_DCHECK_OP(val1, val2, ==)
|
||||
#define TORCH_DCHECK_NE(val1, val2) TORCH_DCHECK_OP(val1, val2, !=)
|
||||
#define TORCH_DCHECK_LE(val1, val2) TORCH_DCHECK_OP(val1, val2, <=)
|
||||
#define TORCH_DCHECK_LT(val1, val2) TORCH_DCHECK_OP(val1, val2, <)
|
||||
#define TORCH_DCHECK_GE(val1, val2) TORCH_DCHECK_OP(val1, val2, >=)
|
||||
#define TORCH_DCHECK_GT(val1, val2) TORCH_DCHECK_OP(val1, val2, >)
|
||||
#else // !NDEBUG
|
||||
// Optimized versions - generate no code
|
||||
#define TORCH_DCHECK_EQ(val1, val2) \
|
||||
while (false) \
|
||||
TORCH_DCHECK_OP(val1, val2, ==)
|
||||
#define TORCH_DCHECK_NE(val1, val2) \
|
||||
while (false) \
|
||||
TORCH_DCHECK_OP(val1, val2, !=)
|
||||
#define TORCH_DCHECK_LE(val1, val2) \
|
||||
while (false) \
|
||||
TORCH_DCHECK_OP(val1, val2, <=)
|
||||
#define TORCH_DCHECK_LT(val1, val2) \
|
||||
while (false) \
|
||||
TORCH_DCHECK_OP(val1, val2, <)
|
||||
#define TORCH_DCHECK_GE(val1, val2) \
|
||||
while (false) \
|
||||
TORCH_DCHECK_OP(val1, val2, >=)
|
||||
#define TORCH_DCHECK_GT(val1, val2) \
|
||||
while (false) \
|
||||
TORCH_DCHECK_OP(val1, val2, >)
|
||||
#endif // NDEBUG
|
||||
|
||||
// Null pointer check macro
|
||||
#define TORCH_CHECK_NOTNULL(val) \
|
||||
::c10::CheckNotNull(__FILE__, __LINE__, #val, (val), false)
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define TORCH_DCHECK_NOTNULL(val) \
|
||||
::c10::CheckNotNull(__FILE__, __LINE__, #val, (val), true)
|
||||
#else // !NDEBUG
|
||||
#define TORCH_DCHECK_NOTNULL(val) \
|
||||
while (false) \
|
||||
TORCH_CHECK_NOTNULL(val)
|
||||
#endif // NDEBUG
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Deprecated macros
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
namespace c10::detail {
|
||||
|
||||
/*
|
||||
// Deprecation disabled until we fix sites in our codebase
|
||||
[[deprecated("AT_ERROR(msg) is deprecated, use TORCH_CHECK(false, msg)
|
||||
instead.")]]
|
||||
*/
|
||||
inline void deprecated_AT_ERROR() {}
|
||||
|
||||
/*
|
||||
// Deprecation disabled until we fix sites in our codebase
|
||||
[[deprecated("AT_ASSERT is deprecated, if you mean to indicate an
|
||||
internal invariant failure, use " \
|
||||
"TORCH_INTERNAL_ASSERT instead; if you mean to do user
|
||||
error checking, use " \ "TORCH_CHECK. See
|
||||
https://github.com/pytorch/pytorch/issues/20287 for more details.")]]
|
||||
*/
|
||||
inline void deprecated_AT_ASSERT() {}
|
||||
|
||||
/*
|
||||
// Deprecation disabled until we fix sites in our codebase
|
||||
[[deprecated("AT_ASSERTM is deprecated, if you mean to indicate an
|
||||
internal invariant failure, use " \
|
||||
"TORCH_INTERNAL_ASSERT instead; if you mean to do user
|
||||
error checking, use " \ "TORCH_CHECK. See
|
||||
https://github.com/pytorch/pytorch/issues/20287 for more details.")]]
|
||||
*/
|
||||
inline void deprecated_AT_ASSERTM() {}
|
||||
|
||||
} // namespace c10::detail
|
||||
|
||||
// Deprecated alias; this alias was deprecated because people kept mistakenly
|
||||
// using it for user error checking. Use TORCH_INTERNAL_ASSERT or TORCH_CHECK
|
||||
// instead. See https://github.com/pytorch/pytorch/issues/20287 for more
|
||||
// details.
|
||||
#define AT_ASSERT(...) \
|
||||
do { \
|
||||
::c10::detail::deprecated_AT_ASSERT(); \
|
||||
C10_EXPAND_MSVC_WORKAROUND(TORCH_INTERNAL_ASSERT(__VA_ARGS__)); \
|
||||
} while (false)
|
||||
|
||||
// Deprecated alias, like AT_ASSERT. The new TORCH_INTERNAL_ASSERT macro
|
||||
// supports both 0-ary and variadic calls, so having a separate
|
||||
// message-accepting macro is not necessary.
|
||||
//
|
||||
// NB: we MUST include cond explicitly here, as MSVC will miscompile the macro
|
||||
// expansion, shunting all of __VA_ARGS__ to cond. An alternate workaround
|
||||
// can be seen at
|
||||
// https://stackoverflow.com/questions/5134523/msvc-doesnt-expand-va-args-correctly
|
||||
#define AT_ASSERTM(cond, ...) \
|
||||
do { \
|
||||
::c10::detail::deprecated_AT_ASSERTM(); \
|
||||
C10_EXPAND_MSVC_WORKAROUND(TORCH_INTERNAL_ASSERT(cond, __VA_ARGS__)); \
|
||||
} while (false)
|
||||
|
||||
// Deprecated alias; this alias was deprecated because it represents extra API
|
||||
// surface that makes it hard for people to understand what macro to use.
|
||||
// Use TORCH_CHECK(false, ...) or TORCH_INTERNAL_ASSERT(false, ...) to
|
||||
// unconditionally fail at a line of code.
|
||||
#define AT_ERROR(...) \
|
||||
do { \
|
||||
::c10::detail::deprecated_AT_ERROR(); \
|
||||
C10_EXPAND_MSVC_WORKAROUND(TORCH_CHECK(false, ::c10::str(__VA_ARGS__))); \
|
||||
} while (false)
|
||||
|
||||
#endif // C10_UTIL_EXCEPTION_H_
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,145 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// See example implementation in TensorBase.h and TensorBody.h.
|
||||
// Synopsis:
|
||||
//
|
||||
// repr_type -- type to use to store an owned T in ExclusivelyOwned.
|
||||
//
|
||||
// pointer_type -- pointer-esque type to return from
|
||||
// ExclusivelyOwned's get() and operator*() methods.
|
||||
//
|
||||
// const_pointer_type -- similar to pointer_type, used for the const methods.
|
||||
//
|
||||
// static repr_type nullRepr() -- return a null instance of repr_type.
|
||||
//
|
||||
// template <class... Args>
|
||||
// static repr_type createInPlace(Args&&... args) -- used by the in-place
|
||||
// ExclusivelyOwned constructor.
|
||||
//
|
||||
// static repr_type moveToRepr(T&& x) -- move the given x into an
|
||||
// instance of repr_type. used by the ExclusivelyOwned(T&&)
|
||||
// constructor.
|
||||
//
|
||||
// static void destroyOwned(repr_type x) -- free memory for a
|
||||
// known-exclusively-owned instance of x. Replaces calling repr_type's
|
||||
// destructor. Being able to implement this more efficiently than
|
||||
// repr_type's destructor is the main reason to use ExclusivelyOwned
|
||||
// for a type.
|
||||
//
|
||||
// static T take(repr_type&) -- move out of the given repr_type into an owned T.
|
||||
//
|
||||
// static pointer_type getImpl(const repr_type&) -- return a pointer
|
||||
// to the given repr_type. May take repr_type by value if that is more
|
||||
// efficient.
|
||||
template <typename T>
|
||||
struct ExclusivelyOwnedTraits;
|
||||
|
||||
/// ExclusivelyOwned is a smart-pointer-like wrapper around an
|
||||
/// exclusively-owned instance of some type T that normally has
|
||||
/// mandatory reference counting (currently just Tensor). If you have
|
||||
/// an isolated piece of code that knows that it has sole ownership of
|
||||
/// an object of one of these types (i.e., because you created it
|
||||
/// directly or using a factory function) and that object will not
|
||||
/// escape from that isolated piece of code, then moving the object
|
||||
/// into an ExclusivelyOwned will avoid an atomic reference count
|
||||
/// decrement at destruction time.
|
||||
///
|
||||
/// If you directly create the Tensor in the first
|
||||
/// place, you can use the in_place constructor of ExclusivelyOwned to
|
||||
/// additionally avoid doing any stores to initialize the refcount &
|
||||
/// weakcount.
|
||||
template <typename T>
|
||||
class ExclusivelyOwned {
|
||||
using EOT = ExclusivelyOwnedTraits<T>;
|
||||
typename ExclusivelyOwnedTraits<T>::repr_type repr_;
|
||||
|
||||
public:
|
||||
ExclusivelyOwned() : repr_(EOT::nullRepr()) {}
|
||||
|
||||
explicit ExclusivelyOwned(T&& t) : repr_(EOT::moveToRepr(std::move(t))) {}
|
||||
|
||||
template <class... Args>
|
||||
explicit ExclusivelyOwned(std::in_place_t /*unused*/, Args&&... args)
|
||||
: repr_(EOT::createInPlace(std::forward<Args>(args)...)) {}
|
||||
|
||||
ExclusivelyOwned(const ExclusivelyOwned&) = delete;
|
||||
|
||||
ExclusivelyOwned(ExclusivelyOwned&& rhs) noexcept
|
||||
: repr_(std::move(rhs.repr_)) {
|
||||
rhs.repr_ = EOT::nullRepr();
|
||||
}
|
||||
|
||||
ExclusivelyOwned& operator=(const ExclusivelyOwned&) = delete;
|
||||
|
||||
ExclusivelyOwned& operator=(ExclusivelyOwned&& rhs) noexcept {
|
||||
EOT::destroyOwned(repr_);
|
||||
repr_ = std::move(rhs.repr_);
|
||||
rhs.repr_ = EOT::nullRepr();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ExclusivelyOwned& operator=(T&& rhs) noexcept {
|
||||
EOT::destroyOwned(repr_);
|
||||
repr_ = EOT::moveToRepr(std::move(rhs));
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ExclusivelyOwned() {
|
||||
EOT::destroyOwned(repr_);
|
||||
// Don't bother to call the destructor of repr_, since we already
|
||||
// did specialized destruction for the exclusively-owned case in
|
||||
// destroyOwned!
|
||||
}
|
||||
|
||||
// We don't provide this because it would require us to be able to
|
||||
// differentiate an owned-but-empty T from a lack of T. This is
|
||||
// particularly problematic for Tensor, which wants to use an
|
||||
// undefined Tensor as its null state.
|
||||
explicit operator bool() const noexcept = delete;
|
||||
|
||||
operator T() && {
|
||||
return take();
|
||||
}
|
||||
|
||||
// NOTE: the equivalent operation on MaybeOwned is a moving
|
||||
// operator*. For ExclusivelyOwned, take() and operator*() may well
|
||||
// have different return types, so they are different functions.
|
||||
T take() && {
|
||||
return EOT::take(repr_);
|
||||
}
|
||||
|
||||
typename EOT::const_pointer_type operator->() const {
|
||||
return get();
|
||||
}
|
||||
|
||||
typename EOT::const_pointer_type get() const {
|
||||
return EOT::getImpl(repr_);
|
||||
}
|
||||
|
||||
typename EOT::pointer_type operator->() {
|
||||
return get();
|
||||
}
|
||||
|
||||
typename EOT::pointer_type get() {
|
||||
return EOT::getImpl(repr_);
|
||||
}
|
||||
|
||||
std::remove_pointer_t<typename EOT::const_pointer_type>& operator*() const {
|
||||
return *get();
|
||||
}
|
||||
|
||||
std::remove_pointer_t<typename EOT::pointer_type>& operator*() {
|
||||
return *get();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/core/TensorImpl.h>
|
||||
#include <c10/core/UndefinedTensorImpl.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace c10 {
|
||||
// Shared ExclusivelyOwnedTraits implementation between caffe2::Tensor and
|
||||
// at::TensorBase.
|
||||
template <typename TensorType>
|
||||
struct ExclusivelyOwnedTensorTraits {
|
||||
using repr_type = TensorType;
|
||||
using pointer_type = TensorType*;
|
||||
using const_pointer_type = const TensorType*;
|
||||
|
||||
static repr_type nullRepr() {
|
||||
return TensorType();
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
static repr_type createInPlace(Args&&... args) {
|
||||
return TensorType(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
static repr_type moveToRepr(TensorType&& x) {
|
||||
return std::move(x);
|
||||
}
|
||||
|
||||
static void destroyOwned(TensorType& x) {
|
||||
TensorImpl* const toDestroy = x.unsafeReleaseTensorImpl();
|
||||
TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
|
||||
toDestroy != nullptr, "Tensor somehow got null TensorImpl?");
|
||||
// May be 0 because UndefinedTensorImpl doesn't get its refcount
|
||||
// incremented.
|
||||
const bool isUndefined = toDestroy == UndefinedTensorImpl::singleton();
|
||||
TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
|
||||
toDestroy->refcount() == 1 ||
|
||||
(toDestroy->refcount() == 0 && isUndefined),
|
||||
"ExclusivelyOwned<Tensor> destroyed with isUndefined ",
|
||||
isUndefined,
|
||||
" and refcount ",
|
||||
toDestroy->refcount(),
|
||||
", expected 1 or, if isUndefined, 0!");
|
||||
TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
|
||||
toDestroy->weakcount() == 1 ||
|
||||
(toDestroy->weakcount() == 0 &&
|
||||
toDestroy == UndefinedTensorImpl::singleton()),
|
||||
"ExclusivelyOwned<Tensor> destroyed with isUndefined ",
|
||||
isUndefined,
|
||||
" and weakcount ",
|
||||
toDestroy->weakcount(),
|
||||
", expected 1 or, if isUndefined, 0!");
|
||||
if (!isUndefined) {
|
||||
#ifndef NDEBUG
|
||||
// Needed to pass the debug assertions in ~intrusive_ptr_target.
|
||||
toDestroy->combined_refcount_.store(0, std::memory_order_relaxed);
|
||||
#endif
|
||||
delete toDestroy;
|
||||
}
|
||||
}
|
||||
|
||||
static TensorType take(TensorType& x) {
|
||||
return std::move(x);
|
||||
}
|
||||
|
||||
static pointer_type getImpl(repr_type& x) {
|
||||
return &x;
|
||||
}
|
||||
|
||||
static const_pointer_type getImpl(const repr_type& x) {
|
||||
return &x;
|
||||
}
|
||||
};
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,34 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#ifndef C10_UTIL_FBCODEMAPS_H_
|
||||
#define C10_UTIL_FBCODEMAPS_H_
|
||||
|
||||
// Map typedefs so that we can use folly's F14 maps in fbcode without
|
||||
// taking a folly dependency.
|
||||
|
||||
#ifdef FBCODE_CAFFE2
|
||||
#include <folly/container/F14Map.h>
|
||||
#include <folly/container/F14Set.h>
|
||||
#else
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#endif
|
||||
|
||||
namespace c10 {
|
||||
#ifdef FBCODE_CAFFE2
|
||||
template <typename Key, typename Value>
|
||||
using FastMap = folly::F14FastMap<Key, Value>;
|
||||
template <typename Key>
|
||||
using FastSet = folly::F14FastSet<Key>;
|
||||
#else
|
||||
template <typename Key, typename Value>
|
||||
using FastMap = std::unordered_map<Key, Value>;
|
||||
template <typename Key>
|
||||
using FastSet = std::unordered_set<Key>;
|
||||
#endif
|
||||
} // namespace c10
|
||||
|
||||
#endif // C10_UTIL_FBCODEMAPS_H_
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,27 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
// Shim header for filesystem for compilers that are too old to have it not
|
||||
// in the experimental namespace
|
||||
|
||||
#if __has_include(<filesystem>)
|
||||
#include <filesystem>
|
||||
#elif __has_include(<experimental/filesystem>)
|
||||
#include <experimental/filesystem>
|
||||
#else
|
||||
#error "Neither <filesystem> nor <experimental/filesystem> is available."
|
||||
#endif
|
||||
|
||||
namespace c10 {
|
||||
|
||||
#if __has_include(<filesystem>)
|
||||
// NOLINTNEXTLINE(misc-unused-alias-decls)
|
||||
namespace filesystem = std::filesystem;
|
||||
#elif __has_include(<experimental/filesystem>)
|
||||
// NOLINTNEXTLINE(misc-unused-alias-decls)
|
||||
namespace filesystem = std::experimental::filesystem;
|
||||
#endif
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,247 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#ifndef C10_UTIL_FLAGS_H_
|
||||
#define C10_UTIL_FLAGS_H_
|
||||
|
||||
/* Commandline flags support for C10.
|
||||
*
|
||||
* This is a portable commandline flags tool for c10, so we can optionally
|
||||
* choose to use gflags or a lightweight custom implementation if gflags is
|
||||
* not possible on a certain platform. If you have gflags installed, set the
|
||||
* macro C10_USE_GFLAGS will seamlessly route everything to gflags.
|
||||
*
|
||||
* To define a flag foo of type bool default to true, do the following in the
|
||||
* *global* namespace:
|
||||
* C10_DEFINE_bool(foo, true, "An example.");
|
||||
*
|
||||
* To use it in another .cc file, you can use C10_DECLARE_* as follows:
|
||||
* C10_DECLARE_bool(foo);
|
||||
*
|
||||
* In both cases, you can then access the flag via FLAGS_foo.
|
||||
*
|
||||
* It is recommended that you build with gflags. To learn more about the flags
|
||||
* usage, refer to the gflags page here:
|
||||
*
|
||||
* https://gflags.github.io/gflags/
|
||||
*
|
||||
* Note about Python users / devs: gflags is initiated from a C++ function
|
||||
* ParseCommandLineFlags, and is usually done in native binaries in the main
|
||||
* function. As Python does not have a modifiable main function, it is usually
|
||||
* difficult to change the flags after Python starts. Hence, it is recommended
|
||||
* that one sets the default value of the flags to one that's acceptable in
|
||||
* general - that will allow Python to run without wrong flags.
|
||||
*/
|
||||
|
||||
#include <c10/macros/Export.h>
|
||||
#include <string>
|
||||
|
||||
#include <c10/util/Registry.h>
|
||||
|
||||
namespace c10 {
|
||||
/**
|
||||
* Sets the usage message when a commandline tool is called with "--help".
|
||||
*/
|
||||
C10_API void SetUsageMessage(const std::string& str);
|
||||
|
||||
/**
|
||||
* Returns the usage message for the commandline tool set by SetUsageMessage.
|
||||
*/
|
||||
C10_API const char* UsageMessage();
|
||||
|
||||
/**
|
||||
* Parses the commandline flags.
|
||||
*
|
||||
* This command parses all the commandline arguments passed in via pargc
|
||||
* and argv. Once it is finished, partc and argv will contain the remaining
|
||||
* commandline args that c10 does not deal with. Note that following
|
||||
* convention, argv[0] contains the binary name and is not parsed.
|
||||
*/
|
||||
C10_API bool ParseCommandLineFlags(int* pargc, char*** pargv);
|
||||
|
||||
/**
|
||||
* Checks if the commandline flags has already been passed.
|
||||
*/
|
||||
C10_API bool CommandLineFlagsHasBeenParsed();
|
||||
|
||||
} // namespace c10
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Below are gflags and non-gflags specific implementations.
|
||||
// In general, they define the following macros for one to declare (use
|
||||
// C10_DECLARE) or define (use C10_DEFINE) flags:
|
||||
// C10_{DECLARE,DEFINE}_{int,int64,double,bool,string}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef C10_USE_GFLAGS
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Begin gflags section: most functions are basically rerouted to gflags.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
// C10 uses hidden visibility by default. However, in gflags, it only uses
|
||||
// export on Windows platform (with dllexport) but not on linux/mac (with
|
||||
// default visibility). As a result, to ensure that we are always exporting
|
||||
// global variables, we will redefine the GFLAGS_DLL_DEFINE_FLAG macro if we
|
||||
// are building C10 as a shared library.
|
||||
// This has to be done after the inclusion of gflags, because some early
|
||||
// versions of gflags.h (e.g. 2.0 on ubuntu 14.04) directly defines the
|
||||
// macros, so we need to do definition after gflags is done.
|
||||
#ifdef GFLAGS_DLL_DEFINE_FLAG
|
||||
#undef GFLAGS_DLL_DEFINE_FLAG
|
||||
#endif // GFLAGS_DLL_DEFINE_FLAG
|
||||
#ifdef GFLAGS_DLL_DECLARE_FLAG
|
||||
#undef GFLAGS_DLL_DECLARE_FLAG
|
||||
#endif // GFLAGS_DLL_DECLARE_FLAG
|
||||
#define GFLAGS_DLL_DEFINE_FLAG C10_EXPORT
|
||||
#define GFLAGS_DLL_DECLARE_FLAG C10_IMPORT
|
||||
|
||||
// gflags before 2.0 uses namespace google and after 2.1 uses namespace gflags.
|
||||
// Using GFLAGS_GFLAGS_H_ to capture this change.
|
||||
#ifndef GFLAGS_GFLAGS_H_
|
||||
namespace gflags = google;
|
||||
#endif // GFLAGS_GFLAGS_H_
|
||||
|
||||
// Motivation about the gflags wrapper:
|
||||
// (1) We would need to make sure that the gflags version and the non-gflags
|
||||
// version of C10 are going to expose the same flags abstraction. One should
|
||||
// explicitly use FLAGS_flag_name to access the flags.
|
||||
// (2) For flag names, it is recommended to start with c10_ to distinguish it
|
||||
// from regular gflags flags. For example, do
|
||||
// C10_DEFINE_BOOL(c10_my_flag, true, "An example");
|
||||
// to allow one to use FLAGS_c10_my_flag.
|
||||
// (3) Gflags has a design issue that does not properly expose the global flags,
|
||||
// if one builds the library with -fvisibility=hidden. The current gflags (as of
|
||||
// Aug 2018) only deals with the Windows case using dllexport, and not the Linux
|
||||
// counterparts. As a result, we will explicitly use C10_EXPORT to export the
|
||||
// flags defined in C10. This is done via a global reference, so the flag
|
||||
// itself is not duplicated - under the hood it is the same global gflags flag.
|
||||
#define C10_GFLAGS_DEF_WRAPPER(type, real_type, name, default_value, help_str) \
|
||||
DEFINE_##type(name, default_value, help_str);
|
||||
|
||||
#define C10_DEFINE_int(name, default_value, help_str) \
|
||||
C10_GFLAGS_DEF_WRAPPER(int32, gflags::int32, name, default_value, help_str)
|
||||
#define C10_DEFINE_int32(name, default_value, help_str) \
|
||||
C10_DEFINE_int(name, default_value, help_str)
|
||||
#define C10_DEFINE_int64(name, default_value, help_str) \
|
||||
C10_GFLAGS_DEF_WRAPPER(int64, gflags::int64, name, default_value, help_str)
|
||||
#define C10_DEFINE_double(name, default_value, help_str) \
|
||||
C10_GFLAGS_DEF_WRAPPER(double, double, name, default_value, help_str)
|
||||
#define C10_DEFINE_bool(name, default_value, help_str) \
|
||||
C10_GFLAGS_DEF_WRAPPER(bool, bool, name, default_value, help_str)
|
||||
#define C10_DEFINE_string(name, default_value, help_str) \
|
||||
C10_GFLAGS_DEF_WRAPPER(string, ::fLS::clstring, name, default_value, help_str)
|
||||
|
||||
// DECLARE_typed_var should be used in header files and in the global namespace.
|
||||
#define C10_GFLAGS_DECLARE_WRAPPER(type, real_type, name) DECLARE_##type(name);
|
||||
|
||||
#define C10_DECLARE_int(name) \
|
||||
C10_GFLAGS_DECLARE_WRAPPER(int32, gflags::int32, name)
|
||||
#define C10_DECLARE_int32(name) C10_DECLARE_int(name)
|
||||
#define C10_DECLARE_int64(name) \
|
||||
C10_GFLAGS_DECLARE_WRAPPER(int64, gflags::int64, name)
|
||||
#define C10_DECLARE_double(name) \
|
||||
C10_GFLAGS_DECLARE_WRAPPER(double, double, name)
|
||||
#define C10_DECLARE_bool(name) C10_GFLAGS_DECLARE_WRAPPER(bool, bool, name)
|
||||
#define C10_DECLARE_string(name) \
|
||||
C10_GFLAGS_DECLARE_WRAPPER(string, ::fLS::clstring, name)
|
||||
|
||||
#define TORCH_DECLARE_int(name) C10_DECLARE_int(name)
|
||||
#define TORCH_DECLARE_int32(name) C10_DECLARE_int32(name)
|
||||
#define TORCH_DECLARE_int64(name) C10_DECLARE_int64(name)
|
||||
#define TORCH_DECLARE_double(name) C10_DECLARE_double(name)
|
||||
#define TORCH_DECLARE_bool(name) C10_DECLARE_bool(name)
|
||||
#define TORCH_DECLARE_string(name) C10_DECLARE_string(name)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// End gflags section.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#else // C10_USE_GFLAGS
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Begin non-gflags section: providing equivalent functionality.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace c10 {
|
||||
|
||||
class C10_API C10FlagParser {
|
||||
public:
|
||||
bool success() {
|
||||
return success_;
|
||||
}
|
||||
|
||||
protected:
|
||||
template <typename T>
|
||||
bool Parse(const std::string& content, T* value);
|
||||
bool success_{false};
|
||||
};
|
||||
|
||||
C10_DECLARE_REGISTRY(C10FlagsRegistry, C10FlagParser, const std::string&);
|
||||
|
||||
} // namespace c10
|
||||
|
||||
// The macros are defined outside the c10 namespace. In your code, you should
|
||||
// write the C10_DEFINE_* and C10_DECLARE_* macros outside any namespace
|
||||
// as well.
|
||||
|
||||
#define C10_DEFINE_typed_var(type, name, default_value, help_str) \
|
||||
C10_EXPORT type FLAGS_##name = default_value; \
|
||||
namespace c10 { \
|
||||
namespace { \
|
||||
class C10FlagParser_##name : public C10FlagParser { \
|
||||
public: \
|
||||
explicit C10FlagParser_##name(const std::string& content) { \
|
||||
success_ = C10FlagParser::Parse<type>(content, &FLAGS_##name); \
|
||||
} \
|
||||
}; \
|
||||
RegistererC10FlagsRegistry g_C10FlagsRegistry_##name( \
|
||||
#name, \
|
||||
C10FlagsRegistry(), \
|
||||
RegistererC10FlagsRegistry::DefaultCreator<C10FlagParser_##name>, \
|
||||
"(" #type ", default " #default_value ") " help_str); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define C10_DEFINE_int(name, default_value, help_str) \
|
||||
C10_DEFINE_typed_var(int, name, default_value, help_str)
|
||||
#define C10_DEFINE_int32(name, default_value, help_str) \
|
||||
C10_DEFINE_int(name, default_value, help_str)
|
||||
#define C10_DEFINE_int64(name, default_value, help_str) \
|
||||
C10_DEFINE_typed_var(int64_t, name, default_value, help_str)
|
||||
#define C10_DEFINE_double(name, default_value, help_str) \
|
||||
C10_DEFINE_typed_var(double, name, default_value, help_str)
|
||||
#define C10_DEFINE_bool(name, default_value, help_str) \
|
||||
C10_DEFINE_typed_var(bool, name, default_value, help_str)
|
||||
#define C10_DEFINE_string(name, default_value, help_str) \
|
||||
C10_DEFINE_typed_var(std::string, name, default_value, help_str)
|
||||
|
||||
// DECLARE_typed_var should be used in header files and in the global namespace.
|
||||
#define C10_DECLARE_typed_var(type, name) C10_API extern type FLAGS_##name
|
||||
|
||||
#define C10_DECLARE_int(name) C10_DECLARE_typed_var(int, name)
|
||||
#define C10_DECLARE_int32(name) C10_DECLARE_int(name)
|
||||
#define C10_DECLARE_int64(name) C10_DECLARE_typed_var(int64_t, name)
|
||||
#define C10_DECLARE_double(name) C10_DECLARE_typed_var(double, name)
|
||||
#define C10_DECLARE_bool(name) C10_DECLARE_typed_var(bool, name)
|
||||
#define C10_DECLARE_string(name) C10_DECLARE_typed_var(std::string, name)
|
||||
|
||||
#define TORCH_DECLARE_typed_var(type, name) TORCH_API extern type FLAGS_##name
|
||||
|
||||
#define TORCH_DECLARE_int(name) TORCH_DECLARE_typed_var(int, name)
|
||||
#define TORCH_DECLARE_int32(name) TORCH_DECLARE_int(name)
|
||||
#define TORCH_DECLARE_int64(name) TORCH_DECLARE_typed_var(int64_t, name)
|
||||
#define TORCH_DECLARE_double(name) TORCH_DECLARE_typed_var(double, name)
|
||||
#define TORCH_DECLARE_bool(name) TORCH_DECLARE_typed_var(bool, name)
|
||||
#define TORCH_DECLARE_string(name) TORCH_DECLARE_typed_var(std::string, name)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// End non-gflags section.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // C10_USE_GFLAGS
|
||||
|
||||
#endif // C10_UTIL_FLAGS_H_
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/Float4_e2m1fn_x2.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/Float8_e4m3fn.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/Float8_e4m3fn.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/Float8_e4m3fnuz.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/Float8_e4m3fnuz.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/Float8_e5m2.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/Float8_e5m2.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/Float8_e5m2fnuz.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/Float8_e5m2fnuz.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/Float8_e8m0fnu.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/Float8_e8m0fnu.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,80 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
//===- llvm/ADT/STLExtras.h - Useful STL related functions ------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains some templates that are useful if you are working with the
|
||||
// STL at all.
|
||||
//
|
||||
// No library is required when using these functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// c10: modified from llvm::function_ref
|
||||
// c10: added more SFINAE to enable use in overloaded functions
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/// An efficient, type-erasing, non-owning reference to a callable. This is
|
||||
/// intended for use as the type of a function parameter that is not used
|
||||
/// after the function in question returns.
|
||||
///
|
||||
/// This class does not own the callable, so it is not in general safe to store
|
||||
/// a function_ref.
|
||||
template <typename Fn>
|
||||
class function_ref;
|
||||
|
||||
template <typename Ret, typename... Params>
|
||||
class function_ref<Ret(Params...)> {
|
||||
Ret (*callback)(intptr_t callable, Params... params) = nullptr;
|
||||
intptr_t callable{};
|
||||
|
||||
template <typename Callable>
|
||||
static Ret callback_fn(intptr_t callable, Params... params) {
|
||||
return (*reinterpret_cast<Callable*>(callable))(
|
||||
std::forward<Params>(params)...);
|
||||
}
|
||||
|
||||
public:
|
||||
function_ref() = default;
|
||||
function_ref(std::nullptr_t) {}
|
||||
|
||||
template <typename Callable>
|
||||
function_ref(
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
|
||||
Callable&& callable,
|
||||
std::enable_if_t<!std::is_same_v<
|
||||
std::remove_reference_t<Callable>,
|
||||
function_ref>>* /*unused*/
|
||||
= nullptr,
|
||||
std::enable_if_t<std::is_convertible_v<
|
||||
typename std::invoke_result_t<Callable, Params...>,
|
||||
Ret>>* /*unused*/
|
||||
= nullptr)
|
||||
: callback(callback_fn<std::remove_reference_t<Callable>>),
|
||||
callable(reinterpret_cast<intptr_t>(&callable)) {}
|
||||
|
||||
Ret operator()(Params... params) const {
|
||||
return callback(callable, std::forward<Params>(params)...);
|
||||
}
|
||||
|
||||
operator bool() const {
|
||||
return callback;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,55 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/SmallVector.h>
|
||||
|
||||
namespace c10::monitor {
|
||||
namespace detail {
|
||||
|
||||
class GaugeImpl;
|
||||
|
||||
class GaugeBackendIf {
|
||||
public:
|
||||
virtual ~GaugeBackendIf() = default;
|
||||
virtual void record(int64_t value) noexcept = 0;
|
||||
};
|
||||
|
||||
class GaugeBackendFactoryIf {
|
||||
public:
|
||||
virtual ~GaugeBackendFactoryIf() = default;
|
||||
|
||||
// May return nullptr if the gauge will be ignored by the given backend.
|
||||
virtual std::unique_ptr<GaugeBackendIf> create(
|
||||
std::string_view key) noexcept = 0;
|
||||
};
|
||||
|
||||
void C10_API
|
||||
registerGaugeBackend(std::unique_ptr<GaugeBackendFactoryIf> /*backend*/);
|
||||
} // namespace detail
|
||||
|
||||
// A handle to a Gauge.
|
||||
class C10_API GaugeHandle {
|
||||
public:
|
||||
explicit GaugeHandle(std::string_view key);
|
||||
void record(int64_t value);
|
||||
|
||||
private:
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
detail::GaugeImpl& impl_;
|
||||
};
|
||||
|
||||
} // namespace c10::monitor
|
||||
|
||||
#define STATIC_GAUGE(_key) \
|
||||
[]() -> ::c10::monitor::GaugeHandle& { \
|
||||
static ::c10::monitor::GaugeHandle handle(#_key); \
|
||||
return handle; \
|
||||
}()
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/Half.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,13 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/Half.h>
|
||||
|
||||
// need to keep the following for BC because the APIs in here were exposed
|
||||
// before migrating Half to torch/headeronly
|
||||
#if (defined(CPU_CAPABILITY_AVX2) || defined(CPU_CAPABILITY_AVX512)) && \
|
||||
!defined(__APPLE__)
|
||||
#include <ATen/cpu/vec/vec_half.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,82 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/**
|
||||
* This template simplifies generation of simple classes that wrap an id
|
||||
* in a typesafe way. Namely, you can use it to create a very lightweight
|
||||
* type that only offers equality comparators and hashing. Example:
|
||||
*
|
||||
* struct MyIdType final : IdWrapper<MyIdType, uint32_t> {
|
||||
* constexpr explicit MyIdType(uint32_t id): IdWrapper(id) {}
|
||||
* };
|
||||
*
|
||||
* Then in the global top level namespace:
|
||||
*
|
||||
* C10_DEFINE_HASH_FOR_IDWRAPPER(MyIdType);
|
||||
*
|
||||
* That's it - equality operators and hash functions are automatically defined
|
||||
* for you, given the underlying type supports it.
|
||||
*/
|
||||
template <class ConcreteType, class UnderlyingType>
|
||||
class IdWrapper {
|
||||
public:
|
||||
using underlying_type = UnderlyingType;
|
||||
using concrete_type = ConcreteType;
|
||||
|
||||
protected:
|
||||
constexpr explicit IdWrapper(underlying_type id) noexcept(
|
||||
noexcept(underlying_type(std::declval<underlying_type>())))
|
||||
: id_(id) {}
|
||||
|
||||
constexpr underlying_type underlyingId() const
|
||||
noexcept(noexcept(underlying_type(std::declval<underlying_type>()))) {
|
||||
return id_;
|
||||
}
|
||||
|
||||
private:
|
||||
friend size_t hash_value(const concrete_type& v) {
|
||||
return std::hash<underlying_type>()(v.id_);
|
||||
}
|
||||
|
||||
// TODO Making operator== noexcept if underlying type is noexcept equality
|
||||
// comparable doesn't work with GCC 4.8.
|
||||
// Fix this once we don't need GCC 4.8 anymore.
|
||||
friend constexpr bool operator==(
|
||||
const concrete_type& lhs,
|
||||
const concrete_type& rhs) noexcept {
|
||||
return lhs.id_ == rhs.id_;
|
||||
}
|
||||
|
||||
// TODO Making operator!= noexcept if operator== is noexcept doesn't work with
|
||||
// GCC 4.8.
|
||||
// Fix this once we don't need GCC 4.8 anymore.
|
||||
friend constexpr bool operator!=(
|
||||
const concrete_type& lhs,
|
||||
const concrete_type& rhs) noexcept {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
underlying_type id_;
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#define C10_DEFINE_HASH_FOR_IDWRAPPER(ClassName) \
|
||||
namespace std { \
|
||||
template <> \
|
||||
struct hash<ClassName> { \
|
||||
size_t operator()(ClassName x) const { \
|
||||
return hash_value(x); \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,211 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/util/Exception.h>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
template <typename T>
|
||||
class IntrusiveList;
|
||||
|
||||
class IntrusiveListHook {
|
||||
template <typename P, typename T>
|
||||
friend class ListIterator;
|
||||
|
||||
template <typename T>
|
||||
friend class IntrusiveList;
|
||||
|
||||
IntrusiveListHook* next_{nullptr};
|
||||
IntrusiveListHook* prev_{nullptr};
|
||||
|
||||
void link_before(IntrusiveListHook* next_node) {
|
||||
next_ = next_node;
|
||||
prev_ = next_node->prev_;
|
||||
next_node->prev_ = this;
|
||||
prev_->next_ = this;
|
||||
}
|
||||
|
||||
public:
|
||||
IntrusiveListHook() : next_(this), prev_(this) {}
|
||||
|
||||
IntrusiveListHook(const IntrusiveListHook&) = delete;
|
||||
IntrusiveListHook& operator=(const IntrusiveListHook&) = delete;
|
||||
IntrusiveListHook(IntrusiveListHook&&) = delete;
|
||||
IntrusiveListHook& operator=(IntrusiveListHook&&) = delete;
|
||||
|
||||
void unlink() {
|
||||
TORCH_CHECK(is_linked());
|
||||
next_->prev_ = prev_;
|
||||
prev_->next_ = next_;
|
||||
next_ = this;
|
||||
prev_ = this;
|
||||
}
|
||||
|
||||
~IntrusiveListHook() {
|
||||
if (is_linked()) {
|
||||
unlink();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_linked() const {
|
||||
return next_ != this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename P, typename T>
|
||||
class ListIterator {
|
||||
static_assert(std::is_same_v<std::remove_const_t<P>, IntrusiveListHook>);
|
||||
static_assert(std::is_base_of_v<IntrusiveListHook, T>);
|
||||
P* ptr_;
|
||||
|
||||
friend class IntrusiveList<T>;
|
||||
|
||||
public:
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = std::conditional_t<std::is_const_v<P>, const T, T>;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
explicit ListIterator(P* ptr) : ptr_(ptr) {}
|
||||
~ListIterator() = default;
|
||||
|
||||
ListIterator(const ListIterator&) = default;
|
||||
ListIterator& operator=(const ListIterator&) = default;
|
||||
ListIterator(ListIterator&&) = default;
|
||||
ListIterator& operator=(ListIterator&&) = default;
|
||||
|
||||
template <
|
||||
typename Q,
|
||||
class = std::enable_if_t<std::is_const_v<P> && !std::is_const_v<Q>>>
|
||||
ListIterator(const ListIterator<Q, T>& rhs) : ptr_(rhs.ptr_) {}
|
||||
|
||||
template <
|
||||
typename Q,
|
||||
class = std::enable_if_t<std::is_const_v<P> && !std::is_const_v<Q>>>
|
||||
ListIterator& operator=(const ListIterator<Q, T>& rhs) {
|
||||
ptr_ = rhs.ptr_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename Q>
|
||||
bool operator==(const ListIterator<Q, T>& other) const {
|
||||
return ptr_ == other.ptr_;
|
||||
}
|
||||
|
||||
template <typename Q>
|
||||
bool operator!=(const ListIterator<Q, T>& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
auto& operator*() const {
|
||||
return static_cast<reference>(*ptr_);
|
||||
}
|
||||
|
||||
ListIterator& operator++() {
|
||||
TORCH_CHECK(ptr_);
|
||||
ptr_ = ptr_->next_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ListIterator& operator--() {
|
||||
TORCH_CHECK(ptr_);
|
||||
ptr_ = ptr_->prev_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto* operator->() const {
|
||||
return static_cast<pointer>(ptr_);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class IntrusiveList {
|
||||
static_assert(std::is_base_of_v<IntrusiveListHook, T>);
|
||||
|
||||
public:
|
||||
IntrusiveList() = default;
|
||||
IntrusiveList(const std::initializer_list<std::reference_wrapper<T>>& items) {
|
||||
for (auto& item : items) {
|
||||
insert(this->end(), item);
|
||||
}
|
||||
}
|
||||
~IntrusiveList() {
|
||||
while (head_.is_linked()) {
|
||||
head_.next_->unlink();
|
||||
}
|
||||
}
|
||||
IntrusiveList(const IntrusiveList&) = delete;
|
||||
IntrusiveList& operator=(const IntrusiveList&) = delete;
|
||||
IntrusiveList(IntrusiveList&&) = delete;
|
||||
IntrusiveList& operator=(IntrusiveList&&) = delete;
|
||||
|
||||
using iterator = ListIterator<IntrusiveListHook, T>;
|
||||
using const_iterator = ListIterator<const IntrusiveListHook, T>;
|
||||
|
||||
auto begin() const {
|
||||
return ++const_iterator{&head_};
|
||||
}
|
||||
|
||||
auto begin() {
|
||||
return ++iterator{&head_};
|
||||
}
|
||||
|
||||
auto end() const {
|
||||
return const_iterator{&head_};
|
||||
}
|
||||
|
||||
auto end() {
|
||||
return iterator{&head_};
|
||||
}
|
||||
|
||||
auto rbegin() const {
|
||||
return std::reverse_iterator{end()};
|
||||
}
|
||||
|
||||
auto rbegin() {
|
||||
return std::reverse_iterator{end()};
|
||||
}
|
||||
|
||||
auto rend() const {
|
||||
return std::reverse_iterator{begin()};
|
||||
}
|
||||
|
||||
auto rend() {
|
||||
return std::reverse_iterator{begin()};
|
||||
}
|
||||
|
||||
auto iterator_to(const T& n) const {
|
||||
return const_iterator{&n};
|
||||
}
|
||||
|
||||
auto iterator_to(T& n) {
|
||||
return iterator{&n};
|
||||
}
|
||||
|
||||
iterator insert(iterator pos, T& n) {
|
||||
n.link_before(pos.ptr_);
|
||||
return iterator{&n};
|
||||
}
|
||||
|
||||
size_t size() const {
|
||||
size_t ret = 0;
|
||||
for ([[maybe_unused]] auto& _ : *this) {
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return !head_.is_linked();
|
||||
}
|
||||
|
||||
private:
|
||||
IntrusiveListHook head_;
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,125 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/**
|
||||
* Thread-safe lazy value with opportunistic concurrency: on concurrent first
|
||||
* access, the factory may be called by multiple threads, but only one result is
|
||||
* stored and its reference returned to all the callers.
|
||||
*
|
||||
* Value is heap-allocated; this optimizes for the case in which the value is
|
||||
* never actually computed.
|
||||
*/
|
||||
template <class T>
|
||||
class OptimisticLazy {
|
||||
public:
|
||||
OptimisticLazy() = default;
|
||||
OptimisticLazy(const OptimisticLazy& other) {
|
||||
if (T* value = other.value_.load(std::memory_order_acquire)) {
|
||||
value_ = new T(*value);
|
||||
}
|
||||
}
|
||||
OptimisticLazy(OptimisticLazy&& other) noexcept
|
||||
: value_(other.value_.exchange(nullptr, std::memory_order_acq_rel)) {}
|
||||
~OptimisticLazy() {
|
||||
reset();
|
||||
}
|
||||
|
||||
template <class Factory>
|
||||
T& ensure(const Factory& factory) {
|
||||
if (T* value = value_.load(std::memory_order_acquire)) {
|
||||
return *value;
|
||||
}
|
||||
T* value = new T(factory());
|
||||
T* old = nullptr;
|
||||
if (!value_.compare_exchange_strong(
|
||||
old, value, std::memory_order_release, std::memory_order_acquire)) {
|
||||
delete value;
|
||||
value = old;
|
||||
}
|
||||
return *value;
|
||||
}
|
||||
|
||||
// The following methods are not thread-safe: they should not be called
|
||||
// concurrently with any other method.
|
||||
|
||||
OptimisticLazy& operator=(const OptimisticLazy& other) {
|
||||
*this = OptimisticLazy{other};
|
||||
return *this;
|
||||
}
|
||||
|
||||
OptimisticLazy& operator=(OptimisticLazy&& other) noexcept {
|
||||
if (this != &other) {
|
||||
reset();
|
||||
value_.store(
|
||||
other.value_.exchange(nullptr, std::memory_order_acquire),
|
||||
std::memory_order_release);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
if (T* old = value_.load(std::memory_order_relaxed)) {
|
||||
value_.store(nullptr, std::memory_order_relaxed);
|
||||
delete old;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<T*> value_{nullptr};
|
||||
};
|
||||
|
||||
/**
|
||||
* Interface for a value that is computed on first access.
|
||||
*/
|
||||
template <class T>
|
||||
class LazyValue {
|
||||
public:
|
||||
virtual ~LazyValue() = default;
|
||||
|
||||
virtual const T& get() const = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convenience thread-safe LazyValue implementation with opportunistic
|
||||
* concurrency.
|
||||
*/
|
||||
template <class T>
|
||||
class OptimisticLazyValue : public LazyValue<T> {
|
||||
public:
|
||||
const T& get() const override {
|
||||
return value_.ensure([this] { return compute(); });
|
||||
}
|
||||
|
||||
private:
|
||||
virtual T compute() const = 0;
|
||||
|
||||
mutable OptimisticLazy<T> value_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convenience immutable (thus thread-safe) LazyValue implementation for cases
|
||||
* in which the value is not actually lazy.
|
||||
*/
|
||||
template <class T>
|
||||
class PrecomputedLazyValue : public LazyValue<T> {
|
||||
public:
|
||||
PrecomputedLazyValue(T value) : value_(std::move(value)) {}
|
||||
|
||||
const T& get() const override {
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
T value_;
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,234 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/Synchronized.h>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct IncrementRAII final {
|
||||
public:
|
||||
explicit IncrementRAII(std::atomic<int32_t>* counter) : _counter(counter) {
|
||||
_counter->fetch_add(1);
|
||||
}
|
||||
|
||||
~IncrementRAII() {
|
||||
_counter->fetch_sub(1);
|
||||
}
|
||||
IncrementRAII(IncrementRAII&&) = delete;
|
||||
IncrementRAII& operator=(IncrementRAII&&) = delete;
|
||||
|
||||
private:
|
||||
std::atomic<int32_t>* _counter;
|
||||
|
||||
C10_DISABLE_COPY_AND_ASSIGN(IncrementRAII);
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// LeftRight wait-free readers synchronization primitive
|
||||
// https://hal.archives-ouvertes.fr/hal-01207881/document
|
||||
//
|
||||
// LeftRight is quite easy to use (it can make an arbitrary
|
||||
// data structure permit wait-free reads), but it has some
|
||||
// particular performance characteristics you should be aware
|
||||
// of if you're deciding to use it:
|
||||
//
|
||||
// - Reads still incur an atomic write (this is how LeftRight
|
||||
// keeps track of how long it needs to keep around the old
|
||||
// data structure)
|
||||
//
|
||||
// - Writes get executed twice, to keep both the left and right
|
||||
// versions up to date. So if your write is expensive or
|
||||
// nondeterministic, this is also an inappropriate structure
|
||||
//
|
||||
// LeftRight is used fairly rarely in PyTorch's codebase. If you
|
||||
// are still not sure if you need it or not, consult your local
|
||||
// C++ expert.
|
||||
//
|
||||
template <class T>
|
||||
class LeftRight final {
|
||||
public:
|
||||
template <class... Args>
|
||||
explicit LeftRight(const Args&... args)
|
||||
: _counters{{{0}, {0}}},
|
||||
_foregroundCounterIndex(0),
|
||||
_foregroundDataIndex(0),
|
||||
_data{{T{args...}, T{args...}}} {}
|
||||
|
||||
// Copying and moving would not be threadsafe.
|
||||
// Needs more thought and careful design to make that work.
|
||||
LeftRight(const LeftRight&) = delete;
|
||||
LeftRight(LeftRight&&) noexcept = delete;
|
||||
LeftRight& operator=(const LeftRight&) = delete;
|
||||
LeftRight& operator=(LeftRight&&) noexcept = delete;
|
||||
|
||||
~LeftRight() {
|
||||
// wait until any potentially running writers are finished
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_writeMutex);
|
||||
}
|
||||
|
||||
// wait until any potentially running readers are finished
|
||||
while (_counters[0].load() != 0 || _counters[1].load() != 0) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
auto read(F&& readFunc) const {
|
||||
detail::IncrementRAII _increment_counter(
|
||||
&_counters[_foregroundCounterIndex.load()]);
|
||||
|
||||
return std::forward<F>(readFunc)(_data[_foregroundDataIndex.load()]);
|
||||
}
|
||||
|
||||
// Throwing an exception in writeFunc is ok but causes the state to be either
|
||||
// the old or the new state, depending on if the first or the second call to
|
||||
// writeFunc threw.
|
||||
template <typename F>
|
||||
auto write(F&& writeFunc) {
|
||||
std::unique_lock<std::mutex> lock(_writeMutex);
|
||||
|
||||
return _write(std::forward<F>(writeFunc));
|
||||
}
|
||||
|
||||
private:
|
||||
template <class F>
|
||||
auto _write(const F& writeFunc) {
|
||||
/*
|
||||
* Assume, A is in background and B in foreground. In simplified terms, we
|
||||
* want to do the following:
|
||||
* 1. Write to A (old background)
|
||||
* 2. Switch A/B
|
||||
* 3. Write to B (new background)
|
||||
*
|
||||
* More detailed algorithm (explanations on why this is important are below
|
||||
* in code):
|
||||
* 1. Write to A
|
||||
* 2. Switch A/B data pointers
|
||||
* 3. Wait until A counter is zero
|
||||
* 4. Switch A/B counters
|
||||
* 5. Wait until B counter is zero
|
||||
* 6. Write to B
|
||||
*/
|
||||
|
||||
auto localDataIndex = _foregroundDataIndex.load();
|
||||
|
||||
// 1. Write to A
|
||||
_callWriteFuncOnBackgroundInstance(writeFunc, localDataIndex);
|
||||
|
||||
// 2. Switch A/B data pointers
|
||||
localDataIndex = localDataIndex ^ 1;
|
||||
_foregroundDataIndex = localDataIndex;
|
||||
|
||||
/*
|
||||
* 3. Wait until A counter is zero
|
||||
*
|
||||
* In the previous write run, A was foreground and B was background.
|
||||
* There was a time after switching _foregroundDataIndex (B to foreground)
|
||||
* and before switching _foregroundCounterIndex, in which new readers could
|
||||
* have read B but incremented A's counter.
|
||||
*
|
||||
* In this current run, we just switched _foregroundDataIndex (A back to
|
||||
* foreground), but before writing to the new background B, we have to make
|
||||
* sure A's counter was zero briefly, so all these old readers are gone.
|
||||
*/
|
||||
auto localCounterIndex = _foregroundCounterIndex.load();
|
||||
_waitForBackgroundCounterToBeZero(localCounterIndex);
|
||||
|
||||
/*
|
||||
* 4. Switch A/B counters
|
||||
*
|
||||
* Now that we know all readers on B are really gone, we can switch the
|
||||
* counters and have new readers increment A's counter again, which is the
|
||||
* correct counter since they're reading A.
|
||||
*/
|
||||
localCounterIndex = localCounterIndex ^ 1;
|
||||
_foregroundCounterIndex = localCounterIndex;
|
||||
|
||||
/*
|
||||
* 5. Wait until B counter is zero
|
||||
*
|
||||
* This waits for all the readers on B that came in while both data and
|
||||
* counter for B was in foreground, i.e. normal readers that happened
|
||||
* outside of that brief gap between switching data and counter.
|
||||
*/
|
||||
_waitForBackgroundCounterToBeZero(localCounterIndex);
|
||||
|
||||
// 6. Write to B
|
||||
return _callWriteFuncOnBackgroundInstance(writeFunc, localDataIndex);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
auto _callWriteFuncOnBackgroundInstance(
|
||||
const F& writeFunc,
|
||||
uint8_t localDataIndex) {
|
||||
try {
|
||||
return writeFunc(_data[localDataIndex ^ 1]);
|
||||
} catch (...) {
|
||||
// recover invariant by copying from the foreground instance
|
||||
_data[localDataIndex ^ 1] = _data[localDataIndex];
|
||||
// rethrow
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void _waitForBackgroundCounterToBeZero(uint8_t counterIndex) {
|
||||
while (_counters[counterIndex ^ 1].load() != 0) {
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
mutable std::array<std::atomic<int32_t>, 2> _counters;
|
||||
std::atomic<uint8_t> _foregroundCounterIndex;
|
||||
std::atomic<uint8_t> _foregroundDataIndex;
|
||||
std::array<T, 2> _data;
|
||||
std::mutex _writeMutex;
|
||||
};
|
||||
|
||||
// RWSafeLeftRightWrapper is API compatible with LeftRight and uses a
|
||||
// read-write lock to protect T (data).
|
||||
template <class T>
|
||||
class RWSafeLeftRightWrapper final {
|
||||
public:
|
||||
template <class... Args>
|
||||
explicit RWSafeLeftRightWrapper(const Args&... args) : data_{args...} {}
|
||||
|
||||
// RWSafeLeftRightWrapper is not copyable or moveable since LeftRight
|
||||
// is not copyable or moveable.
|
||||
RWSafeLeftRightWrapper(const RWSafeLeftRightWrapper&) = delete;
|
||||
RWSafeLeftRightWrapper(RWSafeLeftRightWrapper&&) noexcept = delete;
|
||||
RWSafeLeftRightWrapper& operator=(const RWSafeLeftRightWrapper&) = delete;
|
||||
RWSafeLeftRightWrapper& operator=(RWSafeLeftRightWrapper&&) noexcept = delete;
|
||||
~RWSafeLeftRightWrapper() = default;
|
||||
|
||||
template <typename F>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
|
||||
auto read(F&& readFunc) const {
|
||||
return data_.withLock(
|
||||
[&readFunc](T const& data) { return std::forward<F>(readFunc)(data); });
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-missing-std-forward)
|
||||
auto write(F&& writeFunc) {
|
||||
return data_.withLock(
|
||||
[&writeFunc](T& data) { return std::forward<F>(writeFunc)(data); });
|
||||
}
|
||||
|
||||
private:
|
||||
c10::Synchronized<T> data_;
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,43 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace c10 {
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
struct LoadImpl {
|
||||
C10_HOST_DEVICE static T apply(const void* src) {
|
||||
return *reinterpret_cast<const T*>(src);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct LoadImpl<bool> {
|
||||
C10_HOST_DEVICE static bool apply(const void* src) {
|
||||
static_assert(sizeof(bool) == sizeof(char));
|
||||
// NOTE: [Loading boolean values]
|
||||
// Protect against invalid boolean values by loading as a byte
|
||||
// first, then converting to bool (see gh-54789).
|
||||
return *reinterpret_cast<const unsigned char*>(src);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE constexpr T load(const void* src) {
|
||||
return c10::detail::LoadImpl<T>::apply(src);
|
||||
}
|
||||
|
||||
template <typename scalar_t>
|
||||
C10_HOST_DEVICE constexpr scalar_t load(const scalar_t* src) {
|
||||
return c10::detail::LoadImpl<scalar_t>::apply(src);
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,378 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#ifndef C10_UTIL_LOGGING_H_
|
||||
#define C10_UTIL_LOGGING_H_
|
||||
|
||||
#include <climits>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/Backtrace.h>
|
||||
#include <c10/util/Exception.h>
|
||||
#include <c10/util/Flags.h>
|
||||
#include <c10/util/StringUtil.h>
|
||||
|
||||
// CAFFE2_LOG_THRESHOLD is a compile time flag that would allow us to turn off
|
||||
// logging at compile time so no logging message below that level is produced
|
||||
// at all. The value should be between INT_MIN and CAFFE_FATAL.
|
||||
#ifndef CAFFE2_LOG_THRESHOLD
|
||||
// If we have not defined the compile time log threshold, we keep all the
|
||||
// log cases.
|
||||
#define CAFFE2_LOG_THRESHOLD INT_MIN
|
||||
#endif // CAFFE2_LOG_THRESHOLD
|
||||
|
||||
// Below are different implementations for glog and non-glog cases.
|
||||
#ifdef C10_USE_GLOG
|
||||
#include <c10/util/logging_is_google_glog.h>
|
||||
#else // !C10_USE_GLOG
|
||||
#include <c10/util/logging_is_not_google_glog.h>
|
||||
#endif // C10_USE_GLOG
|
||||
|
||||
C10_DECLARE_int(caffe2_log_level);
|
||||
C10_DECLARE_bool(caffe2_use_fatal_for_enforce);
|
||||
|
||||
// Some versions of GLOG support less-spammy version of LOG_EVERY_MS. If it's
|
||||
// not available - just short-circuit to the always working one one.
|
||||
// We define the C10_ name to avoid confusing other files
|
||||
#ifdef LOG_EVERY_MS
|
||||
#define C10_LOG_EVERY_MS(severity, ms) LOG_EVERY_MS(severity, ms)
|
||||
#else
|
||||
#define C10_LOG_EVERY_MS(severity, ms) LOG(severity)
|
||||
#endif
|
||||
|
||||
// Same for LOG_FIRST_N
|
||||
#ifdef LOG_FIRST_N
|
||||
#define C10_LOG_FIRST_N(severity, n) LOG_FIRST_N(severity, n)
|
||||
#else
|
||||
#define C10_LOG_FIRST_N(severity, n) LOG(severity)
|
||||
#endif
|
||||
|
||||
// Same for LOG_EVERY_N
|
||||
#ifdef LOG_EVERY_N
|
||||
#define C10_LOG_EVERY_N(severity, n) LOG_EVERY_N(severity, n)
|
||||
#else
|
||||
#define C10_LOG_EVERY_N(severity, n) LOG(severity)
|
||||
#endif
|
||||
|
||||
namespace c10 {
|
||||
|
||||
#if !defined(C10_NODEPRECATED)
|
||||
using std::string;
|
||||
#endif
|
||||
|
||||
// Functions that we use for initialization.
|
||||
C10_API bool InitCaffeLogging(int* argc, char** argv);
|
||||
C10_API void UpdateLoggingLevelsFromFlags();
|
||||
|
||||
[[noreturn]] C10_API void ThrowEnforceNotMet(
|
||||
const char* file,
|
||||
const int line,
|
||||
const char* condition,
|
||||
const std::string& msg,
|
||||
const void* caller = nullptr);
|
||||
|
||||
[[noreturn]] C10_API void ThrowEnforceNotMet(
|
||||
const char* file,
|
||||
const int line,
|
||||
const char* condition,
|
||||
const char* msg,
|
||||
const void* caller = nullptr);
|
||||
|
||||
[[noreturn]] inline void ThrowEnforceNotMet(
|
||||
const char* file,
|
||||
const int line,
|
||||
const char* condition,
|
||||
detail::CompileTimeEmptyString /*msg*/,
|
||||
const void* caller = nullptr) {
|
||||
ThrowEnforceNotMet(file, line, condition, "", caller);
|
||||
}
|
||||
|
||||
[[noreturn]] C10_API void ThrowEnforceFiniteNotMet(
|
||||
const char* file,
|
||||
const int line,
|
||||
const char* condition,
|
||||
const std::string& msg,
|
||||
const void* caller = nullptr);
|
||||
|
||||
[[noreturn]] C10_API void ThrowEnforceFiniteNotMet(
|
||||
const char* file,
|
||||
const int line,
|
||||
const char* condition,
|
||||
const char* msg,
|
||||
const void* caller = nullptr);
|
||||
|
||||
[[noreturn]] inline void ThrowEnforceFiniteNotMet(
|
||||
const char* file,
|
||||
const int line,
|
||||
const char* condition,
|
||||
detail::CompileTimeEmptyString /*msg*/,
|
||||
const void* caller = nullptr) {
|
||||
ThrowEnforceFiniteNotMet(file, line, condition, "", caller);
|
||||
}
|
||||
|
||||
constexpr bool IsUsingGoogleLogging() {
|
||||
#ifdef C10_USE_GLOG
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility to allow one to show log info to stderr after the program starts.
|
||||
*
|
||||
* This is similar to calling GLOG's --logtostderr, or setting caffe2_log_level
|
||||
* to smaller than INFO. You are recommended to only use this in a few sparse
|
||||
* cases, such as when you want to write a tutorial or something. Normally, use
|
||||
* the commandline flags to set the log level.
|
||||
*/
|
||||
C10_API void ShowLogInfoToStderr();
|
||||
|
||||
C10_API void SetStackTraceFetcher(std::function<::c10::Backtrace()> fetcher);
|
||||
|
||||
/**
|
||||
* Convenience function for non-lazy stack trace fetchers. The Backtrace
|
||||
* overload should be preferred when stringifying the backtrace is expensive.
|
||||
*/
|
||||
C10_API void SetStackTraceFetcher(std::function<std::string()> fetcher);
|
||||
|
||||
using EnforceNotMet = ::c10::Error;
|
||||
|
||||
#define CAFFE_ENFORCE(condition, ...) \
|
||||
do { \
|
||||
if (C10_UNLIKELY(!(condition))) { \
|
||||
::c10::ThrowEnforceNotMet( \
|
||||
__FILE__, __LINE__, #condition, ::c10::str(__VA_ARGS__)); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define CAFFE_ENFORCE_FINITE(condition, ...) \
|
||||
do { \
|
||||
if (C10_UNLIKELY(!(condition))) { \
|
||||
::c10::ThrowEnforceFiniteNotMet( \
|
||||
__FILE__, __LINE__, #condition, ::c10::str(__VA_ARGS__)); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define CAFFE_ENFORCE_WITH_CALLER(condition, ...) \
|
||||
do { \
|
||||
if (C10_UNLIKELY(!(condition))) { \
|
||||
::c10::ThrowEnforceNotMet( \
|
||||
__FILE__, __LINE__, #condition, ::c10::str(__VA_ARGS__), this); \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define CAFFE_THROW(...) \
|
||||
::c10::ThrowEnforceNotMet(__FILE__, __LINE__, "", ::c10::str(__VA_ARGS__))
|
||||
|
||||
/**
|
||||
* Rich logging messages
|
||||
*
|
||||
* CAFFE_ENFORCE_THAT can be used with one of the "checker functions" that
|
||||
* capture input argument values and add it to the exception message. E.g.
|
||||
* `CAFFE_ENFORCE_THAT(Equals(foo(x), bar(y)), "Optional additional message")`
|
||||
* would evaluate both foo and bar only once and if the results are not equal -
|
||||
* include them in the exception message.
|
||||
*
|
||||
* Some of the basic checker functions like Equals or Greater are already
|
||||
* defined below. Other header might define customized checkers by adding
|
||||
* functions to caffe2::enforce_detail namespace. For example:
|
||||
*
|
||||
* namespace caffe2 { namespace enforce_detail {
|
||||
* inline EnforceFailMessage IsVector(const vector<int64_t>& shape) {
|
||||
* if (shape.size() == 1) { return EnforceOK(); }
|
||||
* return c10::str("Shape ", shape, " is not a vector");
|
||||
* }
|
||||
* }}
|
||||
*
|
||||
* With further usages like `CAFFE_ENFORCE_THAT(IsVector(Input(0).dims()))`
|
||||
*
|
||||
* Convenient wrappers for binary operations like CAFFE_ENFORCE_EQ are provided
|
||||
* too. Please use them instead of TORCH_CHECK_EQ and friends for failures in
|
||||
* user-provided input.
|
||||
*/
|
||||
|
||||
namespace enforce_detail {
|
||||
|
||||
template <typename T1, typename T2>
|
||||
std::string enforceFailMsgImpl(const T1& x, const T2& y) {
|
||||
return c10::str(x, " vs ", y);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename... Args>
|
||||
std::string enforceFailMsgImpl(const T1& x, const T2& y, const Args&... args) {
|
||||
return c10::str(x, " vs ", y, ". ", args...);
|
||||
}
|
||||
|
||||
template <typename Pred, typename T1, typename T2, typename GetFailMsgFunc>
|
||||
void enforceThatImpl(
|
||||
Pred p,
|
||||
const T1& lhs,
|
||||
const T2& rhs,
|
||||
const char* file,
|
||||
int line,
|
||||
const char* expr,
|
||||
const void* caller,
|
||||
GetFailMsgFunc getFailMsg) {
|
||||
if (C10_UNLIKELY(!(p(lhs, rhs)))) {
|
||||
::c10::ThrowEnforceNotMet(file, line, expr, getFailMsg(lhs, rhs), caller);
|
||||
}
|
||||
}
|
||||
|
||||
#define CAFFE_ENFORCE_THAT_IMPL(op, lhs, rhs, expr, ...) \
|
||||
::c10::enforce_detail::enforceThatImpl( \
|
||||
op, \
|
||||
(lhs), \
|
||||
(rhs), \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
expr, \
|
||||
nullptr, \
|
||||
[&](const auto& arg1, const auto& arg2) { \
|
||||
return ::c10::enforce_detail::enforceFailMsgImpl( \
|
||||
arg1, arg2, ##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
#define CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER(op, lhs, rhs, expr, ...) \
|
||||
::c10::enforce_detail::enforceThatImpl( \
|
||||
op, \
|
||||
(lhs), \
|
||||
(rhs), \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
expr, \
|
||||
this, \
|
||||
[&](const auto& arg1, const auto& arg2) { \
|
||||
return ::c10::enforce_detail::enforceFailMsgImpl( \
|
||||
arg1, arg2, ##__VA_ARGS__); \
|
||||
})
|
||||
|
||||
} // namespace enforce_detail
|
||||
|
||||
#define CAFFE_ENFORCE_THAT(cmp, op, lhs, rhs, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL(cmp, lhs, rhs, #lhs " " #op " " #rhs, ##__VA_ARGS__)
|
||||
|
||||
#define CAFFE_ENFORCE_BINARY_OP(cmp, op, x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL(cmp, x, y, #x " " #op " " #y, ##__VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_EQ(x, y, ...) \
|
||||
CAFFE_ENFORCE_BINARY_OP(std::equal_to<void>(), ==, x, y, ##__VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_NE(x, y, ...) \
|
||||
CAFFE_ENFORCE_BINARY_OP(std::not_equal_to<void>(), !=, x, y, ##__VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_LE(x, y, ...) \
|
||||
CAFFE_ENFORCE_BINARY_OP(std::less_equal<void>(), <=, x, y, ##__VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_LT(x, y, ...) \
|
||||
CAFFE_ENFORCE_BINARY_OP(std::less<void>(), <, x, y, ##__VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_GE(x, y, ...) \
|
||||
CAFFE_ENFORCE_BINARY_OP(std::greater_equal<void>(), >=, x, y, ##__VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_GT(x, y, ...) \
|
||||
CAFFE_ENFORCE_BINARY_OP(std::greater<void>(), >, x, y, ##__VA_ARGS__)
|
||||
|
||||
#define CAFFE_ENFORCE_BINARY_OP_WITH_CALLER(cmp, op, x, y, ...) \
|
||||
CAFFE_ENFORCE_THAT_IMPL_WITH_CALLER( \
|
||||
cmp, x, y, #x " " #op " " #y, ##__VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_EQ_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \
|
||||
std::equal_to<void>(), ==, x, y, ##__VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_NE_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \
|
||||
std::not_equal_to<void>(), !=, x, y, ##__VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_LE_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \
|
||||
std::less_equal<void>(), <=, x, y, ##__VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_LT_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_BINARY_OP_WITH_CALLER(std::less<void>(), <, x, y, ##__VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_GE_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \
|
||||
std::greater_equal<void>(), >=, x, y, ##__VA_ARGS__)
|
||||
#define CAFFE_ENFORCE_GT_WITH_CALLER(x, y, ...) \
|
||||
CAFFE_ENFORCE_BINARY_OP_WITH_CALLER( \
|
||||
std::greater<void>(), >, x, y, ##__VA_ARGS__)
|
||||
|
||||
struct IValue;
|
||||
class C10_API EventSampledHandler {
|
||||
public:
|
||||
virtual void log(
|
||||
std::string_view model_id,
|
||||
const std::vector<c10::IValue>& args) = 0;
|
||||
virtual ~EventSampledHandler() = default;
|
||||
};
|
||||
|
||||
#define C10_LOG_EVENT_SAMPLED(event, ...) \
|
||||
static const std::unique_ptr<::c10::EventSampledHandler>& \
|
||||
_##event##EventSampledHandler = ::c10::GetEventSampledHandler(#event); \
|
||||
if (_##event##EventSampledHandler) { \
|
||||
_##event##EventSampledHandler->log(__VA_ARGS__); \
|
||||
}
|
||||
|
||||
// Must be called in the main thread before any other threads are spawned.
|
||||
C10_API void InitEventSampledHandlers(
|
||||
std::vector<std::pair<
|
||||
std::string_view,
|
||||
std::unique_ptr<EventSampledHandler>>> /*handlers*/);
|
||||
C10_API const std::unique_ptr<EventSampledHandler>& GetEventSampledHandler(
|
||||
std::string_view /*event*/);
|
||||
|
||||
/**
|
||||
* Very lightweight logging for the first time API usage. It's beneficial for
|
||||
* tracking of individual functionality usage in larger applications.
|
||||
*
|
||||
* In order to ensure light-weightedness of logging, we utilize static variable
|
||||
* trick - LogAPIUsage will be invoked only once and further invocations will
|
||||
* just do an atomic check.
|
||||
*
|
||||
* Example:
|
||||
* // Logs caller info with an arbitrary text event, if there is a usage.
|
||||
* C10_LOG_API_USAGE_ONCE("my_api");
|
||||
*/
|
||||
#define C10_LOG_API_USAGE_ONCE(...) \
|
||||
[[maybe_unused]] static bool C10_ANONYMOUS_VARIABLE(logFlag) = \
|
||||
::c10::detail::LogAPIUsageFakeReturn(__VA_ARGS__);
|
||||
|
||||
// API usage logging capabilities
|
||||
C10_API void SetAPIUsageLogger(std::function<void(const std::string&)> logger);
|
||||
C10_API void LogAPIUsage(const std::string& context);
|
||||
|
||||
C10_API void SetAPIUsageMetadataLogger(
|
||||
std::function<void(
|
||||
const std::string&,
|
||||
const std::map<std::string, std::string>& metadata_map)> logger);
|
||||
C10_API void LogAPIUsageMetadata(
|
||||
const std::string& context,
|
||||
const std::map<std::string, std::string>& metadata_map);
|
||||
|
||||
// PyTorch ddp usage logging capabilities
|
||||
// DDPLoggingData holds data that can be logged in applications
|
||||
// for analysis and debugging. Data structure is defined in
|
||||
// c10 directory so that it can be easily imported by both c10
|
||||
// and torch files.
|
||||
struct DDPLoggingData {
|
||||
// logging fields that are string types.
|
||||
std::map<std::string, std::string> strs_map;
|
||||
// logging fields that are int64_t types.
|
||||
std::map<std::string, int64_t> ints_map;
|
||||
};
|
||||
|
||||
C10_API void SetPyTorchDDPUsageLogger(
|
||||
std::function<void(const DDPLoggingData&)> logger);
|
||||
C10_API void LogPyTorchDDPUsage(const DDPLoggingData& ddpData);
|
||||
|
||||
namespace detail {
|
||||
// Return value is needed to do the static variable initialization trick
|
||||
C10_API bool LogAPIUsageFakeReturn(const std::string& context);
|
||||
} // namespace detail
|
||||
|
||||
// Initializes the c10 logger.
|
||||
C10_API void initLogging();
|
||||
|
||||
// Sets the rank, which will be included in log messages
|
||||
C10_API void SetGlobalRank(int64_t rank);
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#endif // C10_UTIL_LOGGING_H_
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,147 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/BFloat16.h>
|
||||
#include <c10/util/Half.h>
|
||||
|
||||
C10_CLANG_DIAGNOSTIC_PUSH()
|
||||
#if C10_CLANG_HAS_WARNING("-Wimplicit-float-conversion")
|
||||
C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-float-conversion")
|
||||
#endif
|
||||
|
||||
namespace c10 {
|
||||
// TODO: Replace me with inline constexpr variable when C++17 becomes available
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline constexpr T e() {
|
||||
return static_cast<T>(2.718281828459045235360287471352662);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline constexpr T euler() {
|
||||
return static_cast<T>(0.577215664901532860606512090082402);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline constexpr T frac_1_pi() {
|
||||
return static_cast<T>(0.318309886183790671537767526745028);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline constexpr T frac_1_sqrt_pi() {
|
||||
return static_cast<T>(0.564189583547756286948079451560772);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline constexpr T frac_sqrt_2() {
|
||||
return static_cast<T>(0.707106781186547524400844362104849);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline constexpr T frac_sqrt_3() {
|
||||
return static_cast<T>(0.577350269189625764509148780501957);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline constexpr T golden_ratio() {
|
||||
return static_cast<T>(1.618033988749894848204586834365638);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline constexpr T ln_10() {
|
||||
return static_cast<T>(2.302585092994045684017991454684364);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline constexpr T ln_2() {
|
||||
return static_cast<T>(0.693147180559945309417232121458176);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline constexpr T log_10_e() {
|
||||
return static_cast<T>(0.434294481903251827651128918916605);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline constexpr T log_2_e() {
|
||||
return static_cast<T>(1.442695040888963407359924681001892);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline constexpr T pi() {
|
||||
return static_cast<T>(3.141592653589793238462643383279502);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline constexpr T sqrt_2() {
|
||||
return static_cast<T>(1.414213562373095048801688724209698);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline constexpr T sqrt_3() {
|
||||
return static_cast<T>(1.732050807568877293527446341505872);
|
||||
}
|
||||
|
||||
template <>
|
||||
C10_HOST_DEVICE inline constexpr BFloat16 pi<BFloat16>() {
|
||||
// According to
|
||||
// https://en.wikipedia.org/wiki/Bfloat16_floating-point_format#Special_values
|
||||
// pi is encoded as 4049
|
||||
return BFloat16(0x4049, BFloat16::from_bits());
|
||||
}
|
||||
|
||||
template <>
|
||||
C10_HOST_DEVICE inline constexpr Half pi<Half>() {
|
||||
return Half(0x4248, Half::from_bits());
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
constexpr T e = c10::detail::e<T>();
|
||||
|
||||
template <typename T>
|
||||
constexpr T euler = c10::detail::euler<T>();
|
||||
|
||||
template <typename T>
|
||||
constexpr T frac_1_pi = c10::detail::frac_1_pi<T>();
|
||||
|
||||
template <typename T>
|
||||
constexpr T frac_1_sqrt_pi = c10::detail::frac_1_sqrt_pi<T>();
|
||||
|
||||
template <typename T>
|
||||
constexpr T frac_sqrt_2 = c10::detail::frac_sqrt_2<T>();
|
||||
|
||||
template <typename T>
|
||||
constexpr T frac_sqrt_3 = c10::detail::frac_sqrt_3<T>();
|
||||
|
||||
template <typename T>
|
||||
constexpr T golden_ratio = c10::detail::golden_ratio<T>();
|
||||
|
||||
template <typename T>
|
||||
constexpr T ln_10 = c10::detail::ln_10<T>();
|
||||
|
||||
template <typename T>
|
||||
constexpr T ln_2 = c10::detail::ln_2<T>();
|
||||
|
||||
template <typename T>
|
||||
constexpr T log_10_e = c10::detail::log_10_e<T>();
|
||||
|
||||
template <typename T>
|
||||
constexpr T log_2_e = c10::detail::log_2_e<T>();
|
||||
|
||||
template <typename T>
|
||||
constexpr T pi = c10::detail::pi<T>();
|
||||
|
||||
template <typename T>
|
||||
constexpr T sqrt_2 = c10::detail::sqrt_2<T>();
|
||||
|
||||
template <typename T>
|
||||
constexpr T sqrt_3 = c10::detail::sqrt_3<T>();
|
||||
} // namespace c10
|
||||
|
||||
C10_CLANG_DIAGNOSTIC_POP()
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,242 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/Exception.h>
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/// MaybeOwnedTraits<T> describes how to borrow from T. Here is how we
|
||||
/// can implement borrowing from an arbitrary type T using a raw
|
||||
/// pointer to const:
|
||||
template <typename T>
|
||||
struct MaybeOwnedTraitsGenericImpl {
|
||||
using owned_type = T;
|
||||
using borrow_type = const T*;
|
||||
|
||||
static borrow_type createBorrow(const owned_type& from) {
|
||||
return &from;
|
||||
}
|
||||
|
||||
static void assignBorrow(borrow_type& lhs, borrow_type rhs) {
|
||||
lhs = rhs;
|
||||
}
|
||||
|
||||
static void destroyBorrow(borrow_type& /*toDestroy*/) {}
|
||||
|
||||
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 borrow != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
/// It is possible to eliminate the extra layer of indirection for
|
||||
/// borrows for some types that we control. For examples, see
|
||||
/// intrusive_ptr.h and TensorBody.h.
|
||||
|
||||
template <typename T>
|
||||
struct MaybeOwnedTraits;
|
||||
|
||||
// Explicitly enable MaybeOwned<shared_ptr<T>>, rather than allowing
|
||||
// MaybeOwned to be used for any type right away.
|
||||
template <typename T>
|
||||
struct MaybeOwnedTraits<std::shared_ptr<T>>
|
||||
: public MaybeOwnedTraitsGenericImpl<std::shared_ptr<T>> {};
|
||||
|
||||
/// A smart pointer around either a borrowed or owned T. When
|
||||
/// constructed with borrowed(), the caller MUST ensure that the
|
||||
/// borrowed-from argument outlives this MaybeOwned<T>. Compare to
|
||||
/// Rust's std::borrow::Cow
|
||||
/// (https://doc.rust-lang.org/std/borrow/enum.Cow.html), but note
|
||||
/// that it is probably not suitable for general use because C++ has
|
||||
/// no borrow checking. Included here to support
|
||||
/// Tensor::expect_contiguous.
|
||||
template <typename T>
|
||||
class MaybeOwned final {
|
||||
using borrow_type = typename MaybeOwnedTraits<T>::borrow_type;
|
||||
using owned_type = typename MaybeOwnedTraits<T>::owned_type;
|
||||
|
||||
bool isBorrowed_;
|
||||
union {
|
||||
borrow_type borrow_;
|
||||
owned_type own_;
|
||||
};
|
||||
|
||||
/// Don't use this; use borrowed() instead.
|
||||
explicit MaybeOwned(const owned_type& t)
|
||||
: isBorrowed_(true), borrow_(MaybeOwnedTraits<T>::createBorrow(t)) {}
|
||||
|
||||
/// Don't use this; use owned() instead.
|
||||
explicit MaybeOwned(T&& t) noexcept(std::is_nothrow_move_constructible_v<T>)
|
||||
: isBorrowed_(false), own_(std::move(t)) {}
|
||||
|
||||
/// Don't use this; use owned() instead.
|
||||
template <class... Args>
|
||||
explicit MaybeOwned(std::in_place_t /*unused*/, Args&&... args)
|
||||
: isBorrowed_(false), own_(std::forward<Args>(args)...) {}
|
||||
|
||||
public:
|
||||
explicit MaybeOwned() : isBorrowed_(true), borrow_() {}
|
||||
|
||||
// Copying a borrow yields another borrow of the original, as with a
|
||||
// T*. Copying an owned T yields another owned T for safety: no
|
||||
// chains of borrowing by default! (Note you could get that behavior
|
||||
// with MaybeOwned<T>::borrowed(*rhs) if you wanted it.)
|
||||
MaybeOwned(const MaybeOwned& rhs) : isBorrowed_(rhs.isBorrowed_) {
|
||||
if (C10_LIKELY(rhs.isBorrowed_)) {
|
||||
MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_);
|
||||
} else {
|
||||
new (&own_) T(rhs.own_);
|
||||
}
|
||||
}
|
||||
|
||||
MaybeOwned& operator=(const MaybeOwned& rhs) {
|
||||
if (this == &rhs) {
|
||||
return *this;
|
||||
}
|
||||
if (C10_UNLIKELY(!isBorrowed_)) {
|
||||
if (rhs.isBorrowed_) {
|
||||
own_.~T();
|
||||
MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_);
|
||||
isBorrowed_ = true;
|
||||
} else {
|
||||
own_ = rhs.own_;
|
||||
}
|
||||
} else {
|
||||
if (C10_LIKELY(rhs.isBorrowed_)) {
|
||||
MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_);
|
||||
} else {
|
||||
MaybeOwnedTraits<T>::destroyBorrow(borrow_);
|
||||
new (&own_) T(rhs.own_);
|
||||
isBorrowed_ = false;
|
||||
}
|
||||
}
|
||||
TORCH_INTERNAL_ASSERT_DEBUG_ONLY(isBorrowed_ == rhs.isBorrowed_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
MaybeOwned(MaybeOwned&& rhs) noexcept(
|
||||
// NOLINTNEXTLINE(*-noexcept-move-*)
|
||||
std::is_nothrow_move_constructible_v<T> &&
|
||||
std::is_nothrow_move_assignable_v<borrow_type>)
|
||||
: isBorrowed_(rhs.isBorrowed_) {
|
||||
if (C10_LIKELY(rhs.isBorrowed_)) {
|
||||
MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_);
|
||||
} else {
|
||||
new (&own_) T(std::move(rhs.own_));
|
||||
}
|
||||
}
|
||||
|
||||
MaybeOwned& operator=(MaybeOwned&& rhs) noexcept(
|
||||
std::is_nothrow_move_assignable_v<T> &&
|
||||
std::is_nothrow_move_assignable_v<borrow_type> &&
|
||||
std::is_nothrow_move_constructible_v<T> &&
|
||||
// NOLINTNEXTLINE(*-noexcept-move-*)
|
||||
std::is_nothrow_destructible_v<T> &&
|
||||
std::is_nothrow_destructible_v<borrow_type>) {
|
||||
if (this == &rhs) {
|
||||
return *this;
|
||||
}
|
||||
if (C10_UNLIKELY(!isBorrowed_)) {
|
||||
if (rhs.isBorrowed_) {
|
||||
own_.~T();
|
||||
MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_);
|
||||
isBorrowed_ = true;
|
||||
} else {
|
||||
own_ = std::move(rhs.own_);
|
||||
}
|
||||
} else {
|
||||
if (C10_LIKELY(rhs.isBorrowed_)) {
|
||||
MaybeOwnedTraits<T>::assignBorrow(borrow_, rhs.borrow_);
|
||||
} else {
|
||||
MaybeOwnedTraits<T>::destroyBorrow(borrow_);
|
||||
new (&own_) T(std::move(rhs.own_));
|
||||
isBorrowed_ = false;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
static MaybeOwned borrowed(const T& t) {
|
||||
return MaybeOwned(t);
|
||||
}
|
||||
|
||||
static MaybeOwned owned(T&& t) noexcept(
|
||||
std::is_nothrow_move_constructible_v<T>) {
|
||||
return MaybeOwned(std::move(t));
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
static MaybeOwned owned(std::in_place_t /*unused*/, Args&&... args) {
|
||||
return MaybeOwned(std::in_place, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
~MaybeOwned() noexcept(
|
||||
// NOLINTNEXTLINE(*-noexcept-destructor)
|
||||
std::is_nothrow_destructible_v<T> &&
|
||||
std::is_nothrow_destructible_v<borrow_type>) {
|
||||
if (C10_UNLIKELY(!isBorrowed_)) {
|
||||
own_.~T();
|
||||
} else {
|
||||
MaybeOwnedTraits<T>::destroyBorrow(borrow_);
|
||||
}
|
||||
}
|
||||
|
||||
// This is an implementation detail! You should know what you're doing
|
||||
// if you are testing this. If you just want to guarantee ownership move
|
||||
// this into a T
|
||||
bool unsafeIsBorrowed() const {
|
||||
return isBorrowed_;
|
||||
}
|
||||
|
||||
const T& operator*() const& {
|
||||
if (isBorrowed_) {
|
||||
TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
|
||||
MaybeOwnedTraits<T>::debugBorrowIsValid(borrow_));
|
||||
}
|
||||
return C10_LIKELY(isBorrowed_)
|
||||
? MaybeOwnedTraits<T>::referenceFromBorrow(borrow_)
|
||||
: own_;
|
||||
}
|
||||
|
||||
const T* operator->() const {
|
||||
if (isBorrowed_) {
|
||||
TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
|
||||
MaybeOwnedTraits<T>::debugBorrowIsValid(borrow_));
|
||||
}
|
||||
return C10_LIKELY(isBorrowed_)
|
||||
? MaybeOwnedTraits<T>::pointerFromBorrow(borrow_)
|
||||
: &own_;
|
||||
}
|
||||
|
||||
// If borrowed, copy the underlying T. If owned, move from
|
||||
// it. borrowed/owned state remains the same, and either we
|
||||
// reference the same borrow as before or we are an owned moved-from
|
||||
// T.
|
||||
T operator*() && {
|
||||
if (isBorrowed_) {
|
||||
TORCH_INTERNAL_ASSERT_DEBUG_ONLY(
|
||||
MaybeOwnedTraits<T>::debugBorrowIsValid(borrow_));
|
||||
return MaybeOwnedTraits<T>::referenceFromBorrow(borrow_);
|
||||
} else {
|
||||
return std::move(own_);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/Metaprogramming.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,59 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* This file provides a network flow implementation.
|
||||
* https://en.wikipedia.org/wiki/Flow_network
|
||||
*
|
||||
* It aims to mirror some of the behavior of networkx, which is/was used by
|
||||
* functorch partitioners for splitting the graph into a forward and backward
|
||||
* graph.
|
||||
*/
|
||||
|
||||
namespace c10 {
|
||||
|
||||
enum class C10_API_ENUM MinCutStatus {
|
||||
SUCCESS = 0,
|
||||
UNBOUNDED = 1,
|
||||
OVERFLOW_INF = 2,
|
||||
INVALID = 3,
|
||||
};
|
||||
|
||||
struct MinCutResult {
|
||||
MinCutStatus status;
|
||||
int64_t max_flow;
|
||||
std::vector<std::string> reachable;
|
||||
std::vector<std::string> unreachable;
|
||||
};
|
||||
|
||||
// Modeled after networkx implementation
|
||||
class C10_API NetworkFlowGraph {
|
||||
public:
|
||||
// selected such that INF + INF is < INT64_MAX
|
||||
constexpr static int64_t INF = (1LL << 62) - 1;
|
||||
|
||||
struct Edge {
|
||||
std::string source, dest;
|
||||
int64_t capacity;
|
||||
};
|
||||
|
||||
MinCutStatus add_edge(
|
||||
const std::string& source,
|
||||
const std::string& dest,
|
||||
int64_t capacity = 1);
|
||||
|
||||
MinCutResult minimum_cut(const std::string& s, const std::string& t) const;
|
||||
|
||||
std::vector<Edge> edges;
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,65 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#ifndef C10_UTIL_OPTIONAL_H_
|
||||
#define C10_UTIL_OPTIONAL_H_
|
||||
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
// Macros.h is not needed, but it does namespace shenanigans that lots
|
||||
// of downstream code seems to rely on. Feel free to remove it and fix
|
||||
// up builds.
|
||||
|
||||
namespace c10 {
|
||||
|
||||
#if !defined(FBCODE_CAFFE2) && !defined(C10_NODEPRECATED)
|
||||
// NOLINTNEXTLINE(misc-unused-using-decls)
|
||||
using std::bad_optional_access;
|
||||
// NOLINTNEXTLINE(misc-unused-using-decls)
|
||||
using std::make_optional;
|
||||
// NOLINTNEXTLINE(misc-unused-using-decls)
|
||||
using std::nullopt;
|
||||
// NOLINTNEXTLINE(misc-unused-using-decls)
|
||||
using std::nullopt_t;
|
||||
// NOLINTNEXTLINE(misc-unused-using-decls)
|
||||
using std::optional;
|
||||
#endif
|
||||
|
||||
#if !defined(FBCODE_CAFFE2) && !defined(C10_NODEPRECATED)
|
||||
|
||||
namespace detail_ {
|
||||
// the call to convert<A>(b) has return type A and converts b to type A iff b
|
||||
// decltype(b) is implicitly convertible to A
|
||||
template <class U>
|
||||
constexpr U convert(U v) {
|
||||
return v;
|
||||
}
|
||||
} // namespace detail_
|
||||
template <class T, class F>
|
||||
[[deprecated(
|
||||
"Please use std::optional::value_or instead of c10::value_or_else")]] constexpr T
|
||||
value_or_else(const std::optional<T>& v, F&& func) {
|
||||
static_assert(
|
||||
std::is_convertible_v<typename std::invoke_result_t<F>, T>,
|
||||
"func parameters must be a callable that returns a type convertible to the value stored in the optional");
|
||||
return v.has_value() ? *v : detail_::convert<T>(std::forward<F>(func)());
|
||||
}
|
||||
|
||||
template <class T, class F>
|
||||
[[deprecated(
|
||||
"Please use std::optional::value_or instead of c10::value_or_else")]] constexpr T
|
||||
value_or_else(std::optional<T>&& v, F&& func) {
|
||||
static_assert(
|
||||
std::is_convertible_v<typename std::invoke_result_t<F>, T>,
|
||||
"func parameters must be a callable that returns a type convertible to the value stored in the optional");
|
||||
return v.has_value() ? constexpr_move(std::move(v).contained_val())
|
||||
: detail_::convert<T>(std::forward<F>(func)());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace c10
|
||||
#endif // C10_UTIL_OPTIONAL_H_
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,242 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
// This file defines OptionalArrayRef<T>, a class that has almost the same
|
||||
// exact functionality as std::optional<ArrayRef<T>>, except that its
|
||||
// converting constructor fixes a dangling pointer issue.
|
||||
//
|
||||
// The implicit converting constructor of both std::optional<ArrayRef<T>> and
|
||||
// std::optional<ArrayRef<T>> can cause the underlying ArrayRef<T> to store
|
||||
// a dangling pointer. OptionalArrayRef<T> prevents this by wrapping
|
||||
// a std::optional<ArrayRef<T>> and fixing the constructor implementation.
|
||||
//
|
||||
// See https://github.com/pytorch/pytorch/issues/63645 for more on this.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/util/ArrayRef.h>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
template <typename T>
|
||||
class OptionalArrayRef final {
|
||||
public:
|
||||
// Constructors
|
||||
|
||||
constexpr OptionalArrayRef() noexcept = default;
|
||||
|
||||
constexpr OptionalArrayRef(std::nullopt_t /*unused*/) 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 /*unused*/) 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& {
|
||||
// NOLINTNEXTLINE(bugprone-unchecked-optional-access)
|
||||
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
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,25 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// RAII thread local guard that tracks whether code is being executed in
|
||||
// `at::parallel_for` or `at::parallel_reduce` loop function.
|
||||
class C10_API ParallelGuard {
|
||||
public:
|
||||
static bool is_enabled();
|
||||
|
||||
ParallelGuard(bool state);
|
||||
~ParallelGuard();
|
||||
|
||||
private:
|
||||
bool previous_state_;
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,334 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#ifndef C10_UTIL_REGISTRY_H_
|
||||
#define C10_UTIL_REGISTRY_H_
|
||||
|
||||
/**
|
||||
* Simple registry implementation that uses static variables to
|
||||
* register object creators during program initialization time.
|
||||
*/
|
||||
|
||||
// NB: This Registry works poorly when you have other namespaces.
|
||||
// Make all macro invocations from inside the at namespace.
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <c10/macros/Export.h>
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/Type.h>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
template <typename KeyType>
|
||||
inline std::string KeyStrRepr(const KeyType& /*key*/) {
|
||||
return "[key type printing not supported]";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string KeyStrRepr(const std::string& key) {
|
||||
return key;
|
||||
}
|
||||
|
||||
enum RegistryPriority {
|
||||
REGISTRY_FALLBACK = 1,
|
||||
REGISTRY_DEFAULT = 2,
|
||||
REGISTRY_PREFERRED = 3,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief A template class that allows one to register classes by keys.
|
||||
*
|
||||
* The keys are usually a std::string specifying the name, but can be anything
|
||||
* that can be used in a std::map.
|
||||
*
|
||||
* You should most likely not use the Registry class explicitly, but use the
|
||||
* helper macros below to declare specific registries as well as registering
|
||||
* objects.
|
||||
*/
|
||||
template <class SrcType, class ObjectPtrType, class... Args>
|
||||
class Registry {
|
||||
public:
|
||||
typedef std::function<ObjectPtrType(Args...)> Creator;
|
||||
|
||||
Registry(bool warning = true) : registry_(), priority_(), warning_(warning) {}
|
||||
~Registry() = default;
|
||||
|
||||
void Register(
|
||||
const SrcType& key,
|
||||
Creator creator,
|
||||
const RegistryPriority priority = REGISTRY_DEFAULT) {
|
||||
std::lock_guard<std::mutex> lock(register_mutex_);
|
||||
// The if statement below is essentially the same as the following line:
|
||||
// TORCH_CHECK_EQ(registry_.count(key), 0) << "Key " << key
|
||||
// << " registered twice.";
|
||||
// However, TORCH_CHECK_EQ depends on google logging, and since registration
|
||||
// is carried out at static initialization time, we do not want to have an
|
||||
// explicit dependency on glog's initialization function.
|
||||
if (registry_.count(key) != 0) {
|
||||
auto cur_priority = priority_[key];
|
||||
if (priority > cur_priority) {
|
||||
#ifdef DEBUG
|
||||
std::string warn_msg =
|
||||
"Overwriting already registered item for key " + KeyStrRepr(key);
|
||||
fprintf(stderr, "%s\n", warn_msg.c_str());
|
||||
#endif
|
||||
registry_[key] = creator;
|
||||
priority_[key] = priority;
|
||||
} else if (priority == cur_priority) {
|
||||
std::string err_msg =
|
||||
"Key already registered with the same priority: " + KeyStrRepr(key);
|
||||
fprintf(stderr, "%s\n", err_msg.c_str());
|
||||
if (terminate_) {
|
||||
std::exit(1);
|
||||
} else {
|
||||
throw std::runtime_error(err_msg);
|
||||
}
|
||||
} else if (warning_) {
|
||||
std::string warn_msg =
|
||||
"Higher priority item already registered, skipping registration of " +
|
||||
KeyStrRepr(key);
|
||||
fprintf(stderr, "%s\n", warn_msg.c_str());
|
||||
}
|
||||
} else {
|
||||
registry_[key] = creator;
|
||||
priority_[key] = priority;
|
||||
}
|
||||
}
|
||||
|
||||
void Register(
|
||||
const SrcType& key,
|
||||
Creator creator,
|
||||
const std::string& help_msg,
|
||||
const RegistryPriority priority = REGISTRY_DEFAULT) {
|
||||
Register(key, creator, priority);
|
||||
help_message_[key] = help_msg;
|
||||
}
|
||||
|
||||
inline bool Has(const SrcType& key) {
|
||||
return (registry_.count(key) != 0);
|
||||
}
|
||||
|
||||
ObjectPtrType Create(const SrcType& key, Args... args) {
|
||||
auto it = registry_.find(key);
|
||||
if (it == registry_.end()) {
|
||||
// Returns nullptr if the key is not registered.
|
||||
return nullptr;
|
||||
}
|
||||
return it->second(args...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the keys currently registered as a std::vector.
|
||||
*/
|
||||
std::vector<SrcType> Keys() const {
|
||||
std::vector<SrcType> keys;
|
||||
keys.reserve(registry_.size());
|
||||
for (const auto& it : registry_) {
|
||||
keys.push_back(it.first);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
inline const std::unordered_map<SrcType, std::string>& HelpMessage() const {
|
||||
return help_message_;
|
||||
}
|
||||
|
||||
const char* HelpMessage(const SrcType& key) const {
|
||||
auto it = help_message_.find(key);
|
||||
if (it == help_message_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
return it->second.c_str();
|
||||
}
|
||||
|
||||
// Used for testing, if terminate is unset, Registry throws instead of
|
||||
// calling std::exit
|
||||
void SetTerminate(bool terminate) {
|
||||
terminate_ = terminate;
|
||||
}
|
||||
|
||||
C10_DISABLE_COPY_AND_ASSIGN(Registry);
|
||||
Registry(Registry&&) = delete;
|
||||
Registry& operator=(Registry&&) = delete;
|
||||
|
||||
private:
|
||||
std::unordered_map<SrcType, Creator> registry_;
|
||||
std::unordered_map<SrcType, RegistryPriority> priority_;
|
||||
bool terminate_{true};
|
||||
const bool warning_;
|
||||
std::unordered_map<SrcType, std::string> help_message_;
|
||||
std::mutex register_mutex_;
|
||||
};
|
||||
|
||||
template <class SrcType, class ObjectPtrType, class... Args>
|
||||
class Registerer {
|
||||
public:
|
||||
explicit Registerer(
|
||||
const SrcType& key,
|
||||
Registry<SrcType, ObjectPtrType, Args...>* registry,
|
||||
typename Registry<SrcType, ObjectPtrType, Args...>::Creator creator,
|
||||
const std::string& help_msg = "") {
|
||||
registry->Register(key, creator, help_msg);
|
||||
}
|
||||
|
||||
explicit Registerer(
|
||||
const SrcType& key,
|
||||
const RegistryPriority priority,
|
||||
Registry<SrcType, ObjectPtrType, Args...>* registry,
|
||||
typename Registry<SrcType, ObjectPtrType, Args...>::Creator creator,
|
||||
const std::string& help_msg = "") {
|
||||
registry->Register(key, creator, help_msg, priority);
|
||||
}
|
||||
|
||||
template <class DerivedType>
|
||||
static ObjectPtrType DefaultCreator(Args... args) {
|
||||
return ObjectPtrType(new DerivedType(args...));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* C10_DECLARE_TYPED_REGISTRY is a macro that expands to a function
|
||||
* declaration, as well as creating a convenient typename for its corresponding
|
||||
* registerer.
|
||||
*/
|
||||
// Note on C10_IMPORT and C10_EXPORT below: we need to explicitly mark DECLARE
|
||||
// as import and DEFINE as export, because these registry macros will be used
|
||||
// in downstream shared libraries as well, and one cannot use *_API - the API
|
||||
// macro will be defined on a per-shared-library basis. Semantically, when one
|
||||
// declares a typed registry it is always going to be IMPORT, and when one
|
||||
// defines a registry (which should happen ONLY ONCE and ONLY IN SOURCE FILE),
|
||||
// the instantiation unit is always going to be exported.
|
||||
//
|
||||
// The only unique condition is when in the same file one does DECLARE and
|
||||
// DEFINE - in Windows compilers, this generates a warning that dllimport and
|
||||
// dllexport are mixed, but the warning is fine and linker will be properly
|
||||
// exporting the symbol. Same thing happens in the gflags flag declaration and
|
||||
// definition caes.
|
||||
#define C10_DECLARE_TYPED_REGISTRY( \
|
||||
RegistryName, SrcType, ObjectType, PtrType, ...) \
|
||||
C10_API ::c10::Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>* \
|
||||
RegistryName(); \
|
||||
typedef ::c10::Registerer<SrcType, PtrType<ObjectType>, ##__VA_ARGS__> \
|
||||
Registerer##RegistryName
|
||||
|
||||
#define TORCH_DECLARE_TYPED_REGISTRY( \
|
||||
RegistryName, SrcType, ObjectType, PtrType, ...) \
|
||||
TORCH_API ::c10::Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>* \
|
||||
RegistryName(); \
|
||||
typedef ::c10::Registerer<SrcType, PtrType<ObjectType>, ##__VA_ARGS__> \
|
||||
Registerer##RegistryName
|
||||
|
||||
#define C10_DEFINE_TYPED_REGISTRY( \
|
||||
RegistryName, SrcType, ObjectType, PtrType, ...) \
|
||||
C10_EXPORT ::c10::Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>* \
|
||||
RegistryName() { \
|
||||
static ::c10::Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>* \
|
||||
registry = new ::c10:: \
|
||||
Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>(); \
|
||||
return registry; \
|
||||
}
|
||||
|
||||
#define C10_DEFINE_TYPED_REGISTRY_WITHOUT_WARNING( \
|
||||
RegistryName, SrcType, ObjectType, PtrType, ...) \
|
||||
C10_EXPORT ::c10::Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>* \
|
||||
RegistryName() { \
|
||||
static ::c10::Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>* \
|
||||
registry = \
|
||||
new ::c10::Registry<SrcType, PtrType<ObjectType>, ##__VA_ARGS__>( \
|
||||
false); \
|
||||
return registry; \
|
||||
}
|
||||
|
||||
// Note(Yangqing): The __VA_ARGS__ below allows one to specify a templated
|
||||
// creator with comma in its templated arguments.
|
||||
#define C10_REGISTER_TYPED_CREATOR(RegistryName, key, ...) \
|
||||
static Registerer##RegistryName C10_ANONYMOUS_VARIABLE(g_##RegistryName)( \
|
||||
key, RegistryName(), ##__VA_ARGS__);
|
||||
|
||||
#define C10_REGISTER_TYPED_CREATOR_WITH_PRIORITY( \
|
||||
RegistryName, key, priority, ...) \
|
||||
static Registerer##RegistryName C10_ANONYMOUS_VARIABLE(g_##RegistryName)( \
|
||||
key, priority, RegistryName(), ##__VA_ARGS__);
|
||||
|
||||
#define C10_REGISTER_TYPED_CLASS(RegistryName, key, ...) \
|
||||
static Registerer##RegistryName C10_ANONYMOUS_VARIABLE(g_##RegistryName)( \
|
||||
key, \
|
||||
RegistryName(), \
|
||||
Registerer##RegistryName::DefaultCreator<__VA_ARGS__>, \
|
||||
::c10::demangle_type<__VA_ARGS__>());
|
||||
|
||||
#define C10_REGISTER_TYPED_CLASS_WITH_PRIORITY( \
|
||||
RegistryName, key, priority, ...) \
|
||||
static Registerer##RegistryName C10_ANONYMOUS_VARIABLE(g_##RegistryName)( \
|
||||
key, \
|
||||
priority, \
|
||||
RegistryName(), \
|
||||
Registerer##RegistryName::DefaultCreator<__VA_ARGS__>, \
|
||||
::c10::demangle_type<__VA_ARGS__>());
|
||||
|
||||
// C10_DECLARE_REGISTRY and C10_DEFINE_REGISTRY are hard-wired to use
|
||||
// std::string as the key type, because that is the most commonly used cases.
|
||||
#define C10_DECLARE_REGISTRY(RegistryName, ObjectType, ...) \
|
||||
C10_DECLARE_TYPED_REGISTRY( \
|
||||
RegistryName, std::string, ObjectType, std::unique_ptr, ##__VA_ARGS__)
|
||||
|
||||
#define TORCH_DECLARE_REGISTRY(RegistryName, ObjectType, ...) \
|
||||
TORCH_DECLARE_TYPED_REGISTRY( \
|
||||
RegistryName, std::string, ObjectType, std::unique_ptr, ##__VA_ARGS__)
|
||||
|
||||
#define C10_DEFINE_REGISTRY(RegistryName, ObjectType, ...) \
|
||||
C10_DEFINE_TYPED_REGISTRY( \
|
||||
RegistryName, std::string, ObjectType, std::unique_ptr, ##__VA_ARGS__)
|
||||
|
||||
#define C10_DEFINE_REGISTRY_WITHOUT_WARNING(RegistryName, ObjectType, ...) \
|
||||
C10_DEFINE_TYPED_REGISTRY_WITHOUT_WARNING( \
|
||||
RegistryName, std::string, ObjectType, std::unique_ptr, ##__VA_ARGS__)
|
||||
|
||||
#define C10_DECLARE_SHARED_REGISTRY(RegistryName, ObjectType, ...) \
|
||||
C10_DECLARE_TYPED_REGISTRY( \
|
||||
RegistryName, std::string, ObjectType, std::shared_ptr, ##__VA_ARGS__)
|
||||
|
||||
#define TORCH_DECLARE_SHARED_REGISTRY(RegistryName, ObjectType, ...) \
|
||||
TORCH_DECLARE_TYPED_REGISTRY( \
|
||||
RegistryName, std::string, ObjectType, std::shared_ptr, ##__VA_ARGS__)
|
||||
|
||||
#define C10_DEFINE_SHARED_REGISTRY(RegistryName, ObjectType, ...) \
|
||||
C10_DEFINE_TYPED_REGISTRY( \
|
||||
RegistryName, std::string, ObjectType, std::shared_ptr, ##__VA_ARGS__)
|
||||
|
||||
#define C10_DEFINE_SHARED_REGISTRY_WITHOUT_WARNING( \
|
||||
RegistryName, ObjectType, ...) \
|
||||
C10_DEFINE_TYPED_REGISTRY_WITHOUT_WARNING( \
|
||||
RegistryName, std::string, ObjectType, std::shared_ptr, ##__VA_ARGS__)
|
||||
|
||||
// C10_REGISTER_CREATOR and C10_REGISTER_CLASS are hard-wired to use std::string
|
||||
// as the key
|
||||
// type, because that is the most commonly used cases.
|
||||
#define C10_REGISTER_CREATOR(RegistryName, key, ...) \
|
||||
C10_REGISTER_TYPED_CREATOR(RegistryName, #key, __VA_ARGS__)
|
||||
|
||||
#define C10_REGISTER_CREATOR_WITH_PRIORITY(RegistryName, key, priority, ...) \
|
||||
C10_REGISTER_TYPED_CREATOR_WITH_PRIORITY( \
|
||||
RegistryName, #key, priority, __VA_ARGS__)
|
||||
|
||||
#define C10_REGISTER_CLASS(RegistryName, key, ...) \
|
||||
C10_REGISTER_TYPED_CLASS(RegistryName, #key, __VA_ARGS__)
|
||||
|
||||
#define C10_REGISTER_CLASS_WITH_PRIORITY(RegistryName, key, priority, ...) \
|
||||
C10_REGISTER_TYPED_CLASS_WITH_PRIORITY( \
|
||||
RegistryName, #key, priority, __VA_ARGS__)
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#endif // C10_UTIL_REGISTRY_H_
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,55 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/**
|
||||
* Mostly copied from https://llvm.org/doxygen/ScopeExit_8h_source.html
|
||||
*/
|
||||
template <typename Callable>
|
||||
class scope_exit {
|
||||
Callable ExitFunction;
|
||||
bool Engaged = true; // False once moved-from or release()d.
|
||||
|
||||
public:
|
||||
template <typename Fp>
|
||||
// NOLINTNEXTLINE(bugprone-forwarding-reference-overload)
|
||||
explicit scope_exit(Fp&& F) : ExitFunction(std::forward<Fp>(F)) {}
|
||||
|
||||
scope_exit(scope_exit&& Rhs) noexcept
|
||||
: ExitFunction(std::move(Rhs.ExitFunction)), Engaged(Rhs.Engaged) {
|
||||
Rhs.release();
|
||||
}
|
||||
scope_exit(const scope_exit&) = delete;
|
||||
scope_exit& operator=(scope_exit&&) = delete;
|
||||
scope_exit& operator=(const scope_exit&) = delete;
|
||||
|
||||
void release() {
|
||||
Engaged = false;
|
||||
}
|
||||
|
||||
~scope_exit() {
|
||||
if (Engaged) {
|
||||
ExitFunction();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Keeps the callable object that is passed in, and execute it at the
|
||||
// destruction of the returned object (usually at the scope exit where the
|
||||
// returned object is kept).
|
||||
//
|
||||
// Interface is specified by p0052r2.
|
||||
template <typename Callable>
|
||||
scope_exit<std::decay_t<Callable>> make_scope_exit(Callable&& F) {
|
||||
return scope_exit<std::decay_t<Callable>>(std::forward<Callable>(F));
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,82 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <version>
|
||||
|
||||
/*
|
||||
a simple semaphore interface.
|
||||
*/
|
||||
|
||||
// note: __cpp_lib_semaphore will not be defined in some apple platforms
|
||||
// even if >= C++20.
|
||||
//
|
||||
// libstdc++'s __atomic_semaphore has a lost-wakeup bug: _M_release skips
|
||||
// the futex notify when the counter is already positive, but a concurrent
|
||||
// _S_do_try_acquire can fail its CAS, see zero, and block — missing the
|
||||
// wakeup. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98033
|
||||
#if __has_include(<semaphore>) && defined(__cpp_lib_semaphore) && \
|
||||
__cpp_lib_semaphore >= 201907L && !defined(__GLIBCXX__)
|
||||
#define C10_SEMAPHORE_USE_STL
|
||||
#endif
|
||||
|
||||
#ifdef C10_SEMAPHORE_USE_STL
|
||||
#include <semaphore>
|
||||
#else
|
||||
// To use moodycamel semaphore, we need to include the header file
|
||||
// for concurrentqueue first. Hiding implementation detail here.
|
||||
#ifdef BLOCK_SIZE
|
||||
#pragma push_macro("BLOCK_SIZE")
|
||||
#undef BLOCK_SIZE
|
||||
#include <moodycamel/concurrentqueue.h> // @manual
|
||||
#pragma pop_macro("BLOCK_SIZE")
|
||||
#else
|
||||
#include <moodycamel/concurrentqueue.h> // @manual
|
||||
#endif
|
||||
|
||||
#include <moodycamel/lightweightsemaphore.h> // @manual
|
||||
#endif
|
||||
|
||||
namespace c10 {
|
||||
|
||||
class Semaphore {
|
||||
public:
|
||||
Semaphore(int32_t initial_count = 0) : impl_(initial_count) {}
|
||||
|
||||
void release(int32_t n = 1) {
|
||||
#ifdef C10_SEMAPHORE_USE_STL
|
||||
impl_.release(n);
|
||||
#else
|
||||
impl_.signal(n);
|
||||
#endif
|
||||
}
|
||||
|
||||
void acquire() {
|
||||
#ifdef C10_SEMAPHORE_USE_STL
|
||||
impl_.acquire();
|
||||
#else
|
||||
impl_.wait();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool tryAcquire() {
|
||||
#ifdef C10_SEMAPHORE_USE_STL
|
||||
return impl_.try_acquire();
|
||||
#else
|
||||
return impl_.tryWait();
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef C10_SEMAPHORE_USE_STL
|
||||
std::counting_semaphore<> impl_;
|
||||
#else
|
||||
moodycamel::LightweightSemaphore impl_;
|
||||
#endif
|
||||
};
|
||||
} // namespace c10
|
||||
|
||||
#undef C10_SEMAPHORE_USE_STL
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,92 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <type_traits>
|
||||
|
||||
/** Helper class for allocating temporary fixed size arrays with SBO.
|
||||
*
|
||||
* This is intentionally much simpler than SmallVector, to improve performance
|
||||
* at the expense of many features:
|
||||
* - No zero-initialization for numeric types
|
||||
* - No resizing after construction
|
||||
* - No copy/move
|
||||
* - No non-trivial types
|
||||
*/
|
||||
|
||||
namespace c10 {
|
||||
|
||||
template <typename T, size_t N>
|
||||
class SmallBuffer {
|
||||
static_assert(std::is_trivial_v<T>, "SmallBuffer is intended for POD types");
|
||||
|
||||
std::array<T, N> storage_;
|
||||
size_t size_{};
|
||||
T* data_{};
|
||||
|
||||
public:
|
||||
SmallBuffer(size_t size) : size_(size) {
|
||||
if (size > N) {
|
||||
data_ = new T[size];
|
||||
} else {
|
||||
data_ = &storage_[0];
|
||||
}
|
||||
}
|
||||
|
||||
SmallBuffer(const SmallBuffer&) = delete;
|
||||
SmallBuffer& operator=(const SmallBuffer&) = delete;
|
||||
|
||||
// move constructor is needed in function return
|
||||
SmallBuffer(SmallBuffer&& rhs) noexcept : size_{rhs.size_} {
|
||||
rhs.size_ = 0;
|
||||
if (size_ > N) {
|
||||
data_ = rhs.data_;
|
||||
rhs.data_ = nullptr;
|
||||
} else {
|
||||
storage_ = std::move(rhs.storage_);
|
||||
data_ = &storage_[0];
|
||||
}
|
||||
}
|
||||
|
||||
SmallBuffer& operator=(SmallBuffer&&) = delete;
|
||||
|
||||
~SmallBuffer() {
|
||||
if (size_ > N) {
|
||||
delete[] data_;
|
||||
}
|
||||
}
|
||||
T& operator[](size_t idx) {
|
||||
return data()[idx];
|
||||
}
|
||||
const T& operator[](size_t idx) const {
|
||||
return data()[idx];
|
||||
}
|
||||
T* data() {
|
||||
return data_;
|
||||
}
|
||||
const T* data() const {
|
||||
return data_;
|
||||
}
|
||||
size_t size() const {
|
||||
return size_;
|
||||
}
|
||||
T* begin() {
|
||||
return data_;
|
||||
}
|
||||
const T* begin() const {
|
||||
return data_;
|
||||
}
|
||||
T* end() {
|
||||
return data_ + size_;
|
||||
}
|
||||
const T* end() const {
|
||||
return data_ + size_;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,274 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#ifndef C10_UTIL_STRINGUTIL_H_
|
||||
#define C10_UTIL_STRINGUTIL_H_
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/string_utils.h>
|
||||
|
||||
#include <cstddef>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
C10_CLANG_DIAGNOSTIC_PUSH()
|
||||
#if C10_CLANG_HAS_WARNING("-Wshorten-64-to-32")
|
||||
C10_CLANG_DIAGNOSTIC_IGNORE("-Wshorten-64-to-32")
|
||||
#endif
|
||||
|
||||
namespace c10 {
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Obtains the base name from a full path.
|
||||
C10_API std::string StripBasename(const std::string& full_path);
|
||||
|
||||
C10_API std::string ExcludeFileExtension(const std::string& full_path);
|
||||
|
||||
struct CompileTimeEmptyString {
|
||||
operator const std::string&() const {
|
||||
static const std::string empty_string_literal;
|
||||
return empty_string_literal;
|
||||
}
|
||||
operator const char*() const {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct CanonicalizeStrTypes {
|
||||
using type = const T&;
|
||||
};
|
||||
|
||||
template <size_t N>
|
||||
// NOLINTNEXTLINE(*c-arrays*)
|
||||
struct CanonicalizeStrTypes<char[N]> {
|
||||
using type = const char*;
|
||||
};
|
||||
|
||||
inline std::ostream& _str(std::ostream& ss) {
|
||||
return ss;
|
||||
}
|
||||
|
||||
template <class T, class = std::ostream&>
|
||||
struct Streamable : std::false_type {};
|
||||
|
||||
template <class T>
|
||||
struct Streamable<T, decltype(std::declval<std::ostream&>() << T{})>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
inline std::ostream& _str(std::ostream& ss, const T& t) {
|
||||
if constexpr (std::is_enum_v<T> && !Streamable<T>::value) {
|
||||
// NOLINTNEXTLINE(modernize-type-traits)
|
||||
return _str(ss, static_cast<typename std::underlying_type<T>::type>(t));
|
||||
} else {
|
||||
// NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage)
|
||||
ss << t;
|
||||
return ss;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::ostream& _str(std::ostream& ss, const std::optional<T>& t) {
|
||||
if (t.has_value()) {
|
||||
return _str(ss, t.value());
|
||||
}
|
||||
ss << "std::nullopt";
|
||||
return ss;
|
||||
}
|
||||
// Overloads of _str for wide types; forces narrowing.
|
||||
C10_API std::ostream& _str(std::ostream& ss, const wchar_t* wCStr);
|
||||
C10_API std::ostream& _str(std::ostream& ss, const wchar_t& wChar);
|
||||
C10_API std::ostream& _str(std::ostream& ss, const std::wstring& wString);
|
||||
|
||||
template <>
|
||||
inline std::ostream& _str<CompileTimeEmptyString>(
|
||||
std::ostream& ss,
|
||||
const CompileTimeEmptyString& /*unused*/) {
|
||||
return ss;
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
inline std::ostream& _str(std::ostream& ss, const T& t, const Args&... args) {
|
||||
return _str(_str(ss, t), args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
struct _str_wrapper final {
|
||||
static std::string call(const Args&... args) {
|
||||
std::ostringstream ss;
|
||||
_str(ss, args...);
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
// Specializations for already-a-string types.
|
||||
template <>
|
||||
struct _str_wrapper<std::string> final {
|
||||
// return by reference to avoid the binary size of a string copy
|
||||
static const std::string& call(const std::string& str) {
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct _str_wrapper<const char*> final {
|
||||
static const char* call(const char* str) {
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
// For c10::str() with an empty argument list (which is common in our assert
|
||||
// macros), we don't want to pay the binary size for constructing and
|
||||
// destructing a stringstream or even constructing a string.
|
||||
template <>
|
||||
struct _str_wrapper<> final {
|
||||
static CompileTimeEmptyString call() {
|
||||
return CompileTimeEmptyString();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Convert a list of string-like arguments into a single string.
|
||||
template <typename... Args>
|
||||
inline auto str(const Args&... args) {
|
||||
return detail::_str_wrapper<
|
||||
typename detail::CanonicalizeStrTypes<Args>::type...>::call(args...);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
inline std::string Join(const std::string& delimiter, const Container& v) {
|
||||
std::stringstream s;
|
||||
int cnt = static_cast<int64_t>(v.size()) - 1;
|
||||
for (auto i = v.begin(); i != v.end(); ++i, --cnt) {
|
||||
s << (*i) << (cnt ? delimiter : "");
|
||||
}
|
||||
return std::move(s).str();
|
||||
}
|
||||
|
||||
// Replace all occurrences of "from" substring to "to" string.
|
||||
// Returns number of replacements
|
||||
size_t C10_API
|
||||
ReplaceAll(std::string& s, std::string_view from, std::string_view to);
|
||||
|
||||
/// Represents a location in source code (for debugging).
|
||||
struct C10_API SourceLocation {
|
||||
const char* function;
|
||||
const char* file;
|
||||
uint32_t line;
|
||||
|
||||
static constexpr SourceLocation current(
|
||||
const char* file = __builtin_FILE(),
|
||||
const char* function = __builtin_FUNCTION(),
|
||||
const std::uint_least32_t line = __builtin_LINE()) noexcept {
|
||||
return {function, file, line};
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, const SourceLocation& loc);
|
||||
|
||||
// unix isprint but insensitive to locale
|
||||
inline bool isPrint(char s) {
|
||||
return s > 0x1f && s < 0x7f;
|
||||
}
|
||||
|
||||
inline void printQuotedString(std::ostream& stmt, const std::string_view str) {
|
||||
stmt << '"';
|
||||
for (auto s : str) {
|
||||
switch (s) {
|
||||
case '\\':
|
||||
stmt << "\\\\";
|
||||
break;
|
||||
case '\'':
|
||||
stmt << "\\'";
|
||||
break;
|
||||
case '\"':
|
||||
stmt << "\\\"";
|
||||
break;
|
||||
case '\a':
|
||||
stmt << "\\a";
|
||||
break;
|
||||
case '\b':
|
||||
stmt << "\\b";
|
||||
break;
|
||||
case '\f':
|
||||
stmt << "\\f";
|
||||
break;
|
||||
case '\n':
|
||||
stmt << "\\n";
|
||||
break;
|
||||
case '\r':
|
||||
stmt << "\\r";
|
||||
break;
|
||||
case '\t':
|
||||
stmt << "\\t";
|
||||
break;
|
||||
case '\v':
|
||||
stmt << "\\v";
|
||||
break;
|
||||
default:
|
||||
if (isPrint(s)) {
|
||||
stmt << s;
|
||||
} else {
|
||||
// C++ io has stateful formatting settings. Messing with
|
||||
// them is probably worse than doing this manually.
|
||||
// NOLINTNEXTLINE(*c-arrays*)
|
||||
char buf[4] = "000";
|
||||
// NOLINTNEXTLINE(*narrowing-conversions)
|
||||
buf[2] += s % 8;
|
||||
s /= 8;
|
||||
// NOLINTNEXTLINE(*narrowing-conversions)
|
||||
buf[1] += s % 8;
|
||||
s /= 8;
|
||||
// NOLINTNEXTLINE(*narrowing-conversions)
|
||||
buf[0] += s;
|
||||
stmt << "\\" << buf;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
stmt << '"';
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::optional<T> tryToNumber(const char* symbol) = delete;
|
||||
template <typename T>
|
||||
std::optional<T> tryToNumber(const std::string& symbol) = delete;
|
||||
|
||||
/*
|
||||
* Convert a string to a 64 bit integer. Trailing whitespaces are not supported.
|
||||
* Similarly, integer string with trailing characters like "123abc" will be
|
||||
* rejected.
|
||||
*/
|
||||
template <>
|
||||
C10_API std::optional<int64_t> tryToNumber<int64_t>(const char* symbol);
|
||||
template <>
|
||||
C10_API std::optional<int64_t> tryToNumber<int64_t>(const std::string& symbol);
|
||||
|
||||
/*
|
||||
* Convert a string to a double. Trailing whitespaces are not supported.
|
||||
* Similarly, integer string with trailing characters like "123abc" will
|
||||
* be rejected.
|
||||
*/
|
||||
template <>
|
||||
C10_API std::optional<double> tryToNumber<double>(const char* symbol);
|
||||
template <>
|
||||
C10_API std::optional<double> tryToNumber<double>(const std::string& symbol);
|
||||
|
||||
C10_API std::vector<std::string_view> split(
|
||||
std::string_view target,
|
||||
char delimiter);
|
||||
} // namespace c10
|
||||
|
||||
C10_CLANG_DIAGNOSTIC_POP()
|
||||
|
||||
#endif // C10_UTIL_STRINGUTIL_H_
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,67 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/**
|
||||
* A very simple Synchronization class for error-free use of data
|
||||
* in a multi-threaded context. See folly/docs/Synchronized.md for
|
||||
* the inspiration of this class.
|
||||
*
|
||||
* Full URL:
|
||||
* https://github.com/facebook/folly/blob/main/folly/docs/Synchronized.md
|
||||
*
|
||||
* This class implements a small subset of the generic functionality
|
||||
* implemented by folly:Synchronized<T>. Specifically, only withLock<T>
|
||||
* is implemented here since it's the smallest possible API that is
|
||||
* able to cover a large surface area of functionality offered by
|
||||
* folly::Synchronized<T>.
|
||||
*/
|
||||
template <typename T>
|
||||
class Synchronized final {
|
||||
mutable std::mutex mutex_;
|
||||
T data_;
|
||||
|
||||
public:
|
||||
Synchronized() = default;
|
||||
Synchronized(T const& data) : data_(data) {}
|
||||
Synchronized(T&& data) : data_(std::move(data)) {}
|
||||
|
||||
// Don't permit copy construction, move, assignment, or
|
||||
// move assignment, since the underlying std::mutex
|
||||
// isn't necessarily copyable/moveable.
|
||||
Synchronized(Synchronized const&) = delete;
|
||||
Synchronized(Synchronized&&) = delete;
|
||||
Synchronized operator=(Synchronized const&) = delete;
|
||||
Synchronized operator=(Synchronized&&) = delete;
|
||||
~Synchronized() = default;
|
||||
|
||||
/**
|
||||
* To use, call withLock<T> with a callback that accepts T either
|
||||
* by copy or by reference. Use the protected variable in the
|
||||
* provided callback safely.
|
||||
*/
|
||||
template <typename CB>
|
||||
auto withLock(CB&& cb) {
|
||||
std::lock_guard<std::mutex> guard(this->mutex_);
|
||||
return std::forward<CB>(cb)(this->data_);
|
||||
}
|
||||
|
||||
/**
|
||||
* To use, call withLock<T> with a callback that accepts T either
|
||||
* by copy or by const reference. Use the protected variable in
|
||||
* the provided callback safely.
|
||||
*/
|
||||
template <typename CB>
|
||||
auto withLock(CB&& cb) const {
|
||||
std::lock_guard<std::mutex> guard(this->mutex_);
|
||||
return std::forward<CB>(cb)(this->data_);
|
||||
}
|
||||
};
|
||||
} // end namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,161 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
|
||||
/**
|
||||
* Android versions with libgnustl incorrectly handle thread_local C++
|
||||
* qualifier with composite types. NDK up to r17 version is affected.
|
||||
*
|
||||
* (A fix landed on Jun 4 2018:
|
||||
* https://android-review.googlesource.com/c/toolchain/gcc/+/683601)
|
||||
*
|
||||
* In such cases, use c10::ThreadLocal<T> wrapper
|
||||
* which is `pthread_*` based with smart pointer semantics.
|
||||
*
|
||||
* In addition, convenient macro C10_DEFINE_TLS_static is available.
|
||||
* To define static TLS variable of type std::string, do the following
|
||||
* ```
|
||||
* C10_DEFINE_TLS_static(std::string, str_tls_);
|
||||
* ///////
|
||||
* {
|
||||
* *str_tls_ = "abc";
|
||||
* assert(str_tls_->length(), 3);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* (see c10/test/util/ThreadLocal_test.cpp for more examples)
|
||||
*/
|
||||
#if !defined(C10_PREFER_CUSTOM_THREAD_LOCAL_STORAGE)
|
||||
|
||||
#if defined(C10_ANDROID) && defined(__GLIBCXX__) && __GLIBCXX__ < 20180604
|
||||
#define C10_PREFER_CUSTOM_THREAD_LOCAL_STORAGE
|
||||
#endif // defined(C10_ANDROID) && defined(__GLIBCXX__) && __GLIBCXX__ < 20180604
|
||||
|
||||
#endif // !defined(C10_PREFER_CUSTOM_THREAD_LOCAL_STORAGE)
|
||||
|
||||
#if defined(C10_PREFER_CUSTOM_THREAD_LOCAL_STORAGE)
|
||||
#include <c10/util/Exception.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <memory>
|
||||
namespace c10 {
|
||||
|
||||
/**
|
||||
* @brief Temporary thread_local C++ qualifier replacement for Android
|
||||
* based on `pthread_*`.
|
||||
* To be used with composite types that provide default ctor.
|
||||
*/
|
||||
template <typename Type>
|
||||
class ThreadLocal {
|
||||
public:
|
||||
ThreadLocal() {
|
||||
pthread_key_create(
|
||||
&key_, [](void* buf) { delete static_cast<Type*>(buf); });
|
||||
}
|
||||
|
||||
~ThreadLocal() {
|
||||
if (void* current = pthread_getspecific(key_)) {
|
||||
delete static_cast<Type*>(current);
|
||||
}
|
||||
|
||||
pthread_key_delete(key_);
|
||||
}
|
||||
|
||||
ThreadLocal(const ThreadLocal&) = delete;
|
||||
ThreadLocal& operator=(const ThreadLocal&) = delete;
|
||||
|
||||
Type& get() {
|
||||
if (void* current = pthread_getspecific(key_)) {
|
||||
return *static_cast<Type*>(current);
|
||||
}
|
||||
|
||||
std::unique_ptr<Type> ptr = std::make_unique<Type>();
|
||||
if (0 == pthread_setspecific(key_, ptr.get())) {
|
||||
return *ptr.release();
|
||||
}
|
||||
|
||||
int err = errno;
|
||||
TORCH_INTERNAL_ASSERT(false, "pthread_setspecific() failed, errno = ", err);
|
||||
}
|
||||
|
||||
Type& operator*() {
|
||||
return get();
|
||||
}
|
||||
|
||||
Type* operator->() {
|
||||
return &get();
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_key_t key_;
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#define C10_DEFINE_TLS_static(Type, Name) static ::c10::ThreadLocal<Type> Name
|
||||
|
||||
#define C10_DECLARE_TLS_class_static(Class, Type, Name) \
|
||||
static ::c10::ThreadLocal<Type> Name
|
||||
|
||||
#define C10_DEFINE_TLS_class_static(Class, Type, Name) \
|
||||
::c10::ThreadLocal<Type> Class::Name
|
||||
|
||||
#else // defined(C10_PREFER_CUSTOM_THREAD_LOCAL_STORAGE)
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/**
|
||||
* @brief Default thread_local implementation for non-Android cases.
|
||||
* To be used with composite types that provide default ctor.
|
||||
*/
|
||||
template <typename Type>
|
||||
class ThreadLocal {
|
||||
public:
|
||||
using Accessor = Type* (*)();
|
||||
explicit ThreadLocal(Accessor accessor) : accessor_(accessor) {}
|
||||
|
||||
ThreadLocal(const ThreadLocal&) = delete;
|
||||
ThreadLocal(ThreadLocal&&) noexcept = default;
|
||||
ThreadLocal& operator=(const ThreadLocal&) = delete;
|
||||
ThreadLocal& operator=(ThreadLocal&&) noexcept = default;
|
||||
~ThreadLocal() = default;
|
||||
|
||||
Type& get() {
|
||||
return *accessor_();
|
||||
}
|
||||
|
||||
Type& operator*() {
|
||||
return get();
|
||||
}
|
||||
|
||||
Type* operator->() {
|
||||
return &get();
|
||||
}
|
||||
|
||||
private:
|
||||
Accessor accessor_;
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#define C10_DEFINE_TLS_static(Type, Name) \
|
||||
static ::c10::ThreadLocal<Type> Name([]() { \
|
||||
static thread_local Type var; \
|
||||
return &var; \
|
||||
})
|
||||
|
||||
#define C10_DECLARE_TLS_class_static(Class, Type, Name) \
|
||||
static ::c10::ThreadLocal<Type> Name
|
||||
|
||||
#define C10_DEFINE_TLS_class_static(Class, Type, Name) \
|
||||
::c10::ThreadLocal<Type> Class::Name([]() { \
|
||||
static thread_local Type var; \
|
||||
return &var; \
|
||||
})
|
||||
|
||||
#endif // defined(C10_PREFER_CUSTOM_THREAD_LOCAL_STORAGE)
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Export.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
enum class C10_API_ENUM DebugInfoKind : uint8_t {
|
||||
PRODUCER_INFO = 0,
|
||||
MOBILE_RUNTIME_INFO,
|
||||
PROFILER_STATE,
|
||||
INFERENCE_CONTEXT, // for inference usage
|
||||
PARAM_COMMS_INFO,
|
||||
|
||||
TEST_INFO, // used only in tests
|
||||
TEST_INFO_2, // used only in tests
|
||||
};
|
||||
|
||||
class C10_API DebugInfoBase {
|
||||
public:
|
||||
DebugInfoBase() = default;
|
||||
virtual ~DebugInfoBase() = default;
|
||||
};
|
||||
|
||||
// Thread local debug information is propagated across the forward
|
||||
// (including async fork tasks) and backward passes and is supposed
|
||||
// to be utilized by the user's code to pass extra information from
|
||||
// the higher layers (e.g. model id) down to the lower levels
|
||||
// (e.g. to the operator observers used for debugging, logging,
|
||||
// profiling, etc)
|
||||
class C10_API ThreadLocalDebugInfo {
|
||||
public:
|
||||
static DebugInfoBase* get(DebugInfoKind kind);
|
||||
|
||||
// Get current ThreadLocalDebugInfo
|
||||
static std::shared_ptr<ThreadLocalDebugInfo> current();
|
||||
|
||||
// Internal, use DebugInfoGuard/ThreadLocalStateGuard
|
||||
static void _forceCurrentDebugInfo(
|
||||
std::shared_ptr<ThreadLocalDebugInfo> info);
|
||||
|
||||
// Push debug info struct of a given kind
|
||||
static void _push(DebugInfoKind kind, std::shared_ptr<DebugInfoBase> info);
|
||||
// Pop debug info, throws in case the last pushed
|
||||
// debug info is not of a given kind
|
||||
static std::shared_ptr<DebugInfoBase> _pop(DebugInfoKind kind);
|
||||
// Peek debug info, throws in case the last pushed debug info is not of the
|
||||
// given kind
|
||||
static std::shared_ptr<DebugInfoBase> _peek(DebugInfoKind kind);
|
||||
|
||||
private:
|
||||
std::shared_ptr<DebugInfoBase> info_;
|
||||
DebugInfoKind kind_;
|
||||
std::shared_ptr<ThreadLocalDebugInfo> parent_info_;
|
||||
|
||||
friend class DebugInfoGuard;
|
||||
};
|
||||
|
||||
// DebugInfoGuard is used to set debug information,
|
||||
// ThreadLocalDebugInfo is semantically immutable, the values are set
|
||||
// through the scope-based guard object.
|
||||
// Nested DebugInfoGuard adds/overrides existing values in the scope,
|
||||
// restoring the original values after exiting the scope.
|
||||
// Users can access the values through the ThreadLocalDebugInfo::get() call;
|
||||
class C10_API DebugInfoGuard {
|
||||
public:
|
||||
DebugInfoGuard(DebugInfoKind kind, std::shared_ptr<DebugInfoBase> info);
|
||||
|
||||
explicit DebugInfoGuard(std::shared_ptr<ThreadLocalDebugInfo> info);
|
||||
|
||||
~DebugInfoGuard();
|
||||
|
||||
DebugInfoGuard(const DebugInfoGuard&) = delete;
|
||||
DebugInfoGuard(DebugInfoGuard&&) = delete;
|
||||
DebugInfoGuard& operator=(const DebugInfoGuard&) = delete;
|
||||
DebugInfoGuard& operator=(DebugInfoGuard&&) = delete;
|
||||
|
||||
private:
|
||||
bool active_ = false;
|
||||
std::shared_ptr<ThreadLocalDebugInfo> prev_info_ = nullptr;
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,35 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#ifndef C10_UTIL_TYPE_H_
|
||||
#define C10_UTIL_TYPE_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#ifdef __GXX_RTTI
|
||||
#include <typeinfo>
|
||||
#endif // __GXX_RTTI
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/// Utility to demangle a C++ symbol name.
|
||||
C10_API std::string demangle(const char* name);
|
||||
|
||||
/// Returns the printable name of the type.
|
||||
template <typename T>
|
||||
inline const char* demangle_type() {
|
||||
#ifdef __GXX_RTTI
|
||||
static const auto& name = *(new std::string(demangle(typeid(T).name())));
|
||||
return name.c_str();
|
||||
#else // __GXX_RTTI
|
||||
return "(RTTI disabled, cannot show name)";
|
||||
#endif // __GXX_RTTI
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#endif // C10_UTIL_TYPE_H_
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,215 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/BFloat16.h>
|
||||
#include <c10/util/Float8_e4m3fn.h>
|
||||
#include <c10/util/Float8_e4m3fnuz.h>
|
||||
#include <c10/util/Float8_e5m2.h>
|
||||
#include <c10/util/Float8_e5m2fnuz.h>
|
||||
#include <c10/util/Float8_e8m0fnu.h>
|
||||
#include <c10/util/Half.h>
|
||||
#include <c10/util/complex.h>
|
||||
#include <c10/util/overflows.h>
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
C10_CLANG_DIAGNOSTIC_PUSH()
|
||||
#if C10_CLANG_HAS_WARNING("-Wimplicit-float-conversion")
|
||||
C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-float-conversion")
|
||||
#endif
|
||||
#if C10_CLANG_HAS_WARNING("-Wimplicit-int-float-conversion")
|
||||
C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-int-float-conversion")
|
||||
#endif
|
||||
|
||||
namespace c10 {
|
||||
|
||||
template <typename dest_t, typename src_t>
|
||||
struct needs_real {
|
||||
constexpr static bool value =
|
||||
(is_complex<src_t>::value && !is_complex<dest_t>::value);
|
||||
};
|
||||
|
||||
template <bool, typename src_t>
|
||||
struct maybe_real {
|
||||
C10_HOST_DEVICE static inline src_t apply(src_t src) {
|
||||
return src;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename src_t>
|
||||
struct maybe_real<true, src_t> {
|
||||
C10_HOST_DEVICE static inline decltype(auto) apply(src_t src) {
|
||||
return src.real();
|
||||
}
|
||||
};
|
||||
|
||||
template <bool, typename src_t>
|
||||
struct maybe_bool {
|
||||
C10_HOST_DEVICE static inline src_t apply(src_t src) {
|
||||
return src;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename src_t>
|
||||
struct maybe_bool<true, src_t> {
|
||||
C10_HOST_DEVICE static inline decltype(auto) apply(src_t src) {
|
||||
// Don't use bool operator so as to also compile for ComplexHalf.
|
||||
return src.real() || src.imag();
|
||||
}
|
||||
};
|
||||
|
||||
// Note: deliberately ignores undefined behavior, consistent with NumPy.
|
||||
// PyTorch's type conversions can cause a variety of undefined behavior,
|
||||
// including float to integral overflow and signed to unsigned integer overflow.
|
||||
// Some of this undefined behavior is addressed below.
|
||||
template <typename dest_t, typename src_t>
|
||||
struct static_cast_with_inter_type {
|
||||
C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline dest_t apply(
|
||||
src_t src) {
|
||||
constexpr bool real = needs_real<dest_t, src_t>::value;
|
||||
auto r = maybe_real<real, src_t>::apply(src);
|
||||
return static_cast<dest_t>(r);
|
||||
}
|
||||
};
|
||||
|
||||
// Partial template specialization for casting to bool.
|
||||
// Need to handle complex types separately, as we don't
|
||||
// simply want to cast the real part to bool.
|
||||
template <typename src_t>
|
||||
struct static_cast_with_inter_type<bool, src_t> {
|
||||
C10_HOST_DEVICE static inline bool apply(src_t src) {
|
||||
constexpr bool complex = needs_real<bool, src_t>::value;
|
||||
return static_cast<bool>(maybe_bool<complex, src_t>::apply(src));
|
||||
}
|
||||
};
|
||||
|
||||
// Partial template instantiation for casting to uint8.
|
||||
// Note: Converting from negative float values to unsigned integer types is
|
||||
// undefined behavior in C++, and current CPU and GPU compilers exhibit
|
||||
// divergent behavior. Casting from negative float values to signed
|
||||
// integer types and then to unsigned integer types is not undefined,
|
||||
// however, so this cast improves the consistency of type conversions
|
||||
// to uint8 across compilers.
|
||||
// Further note: Type conversions across compilers still have other undefined
|
||||
// and divergent behavior.
|
||||
template <typename src_t>
|
||||
struct static_cast_with_inter_type<uint8_t, src_t> {
|
||||
C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline uint8_t apply(
|
||||
src_t src) {
|
||||
constexpr bool real = needs_real<uint8_t, src_t>::value;
|
||||
return static_cast<uint8_t>(
|
||||
static_cast<int64_t>(maybe_real<real, src_t>::apply(src)));
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct static_cast_with_inter_type<c10::complex<c10::Half>, c10::BFloat16> {
|
||||
C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex<
|
||||
c10::Half>
|
||||
apply(c10::BFloat16 src) {
|
||||
return static_cast<c10::complex<c10::Half>>(c10::complex<float>{src});
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct static_cast_with_inter_type<c10::complex<c10::Half>, c10::Float8_e5m2> {
|
||||
C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex<
|
||||
c10::Half>
|
||||
apply(c10::Float8_e5m2 src) {
|
||||
return static_cast<c10::complex<c10::Half>>(c10::complex<float>{src});
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct static_cast_with_inter_type<
|
||||
c10::complex<c10::Half>,
|
||||
c10::Float8_e5m2fnuz> {
|
||||
C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex<
|
||||
c10::Half>
|
||||
apply(c10::Float8_e5m2fnuz src) {
|
||||
return static_cast<c10::complex<c10::Half>>(c10::complex<float>{src});
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct static_cast_with_inter_type<
|
||||
c10::complex<c10::Half>,
|
||||
c10::Float8_e4m3fn> {
|
||||
C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex<
|
||||
c10::Half>
|
||||
apply(c10::Float8_e4m3fn src) {
|
||||
return static_cast<c10::complex<c10::Half>>(c10::complex<float>{src});
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct static_cast_with_inter_type<
|
||||
c10::complex<c10::Half>,
|
||||
c10::Float8_e4m3fnuz> {
|
||||
C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex<
|
||||
c10::Half>
|
||||
apply(c10::Float8_e4m3fnuz src) {
|
||||
return static_cast<c10::complex<c10::Half>>(c10::complex<float>{src});
|
||||
}
|
||||
};
|
||||
|
||||
// TODO(#146647): Can we make all these template specialization happen
|
||||
// based off our apply macros?
|
||||
template <>
|
||||
struct static_cast_with_inter_type<
|
||||
c10::complex<c10::Half>,
|
||||
c10::Float8_e8m0fnu> {
|
||||
C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex<
|
||||
c10::Half>
|
||||
apply(c10::Float8_e8m0fnu src) {
|
||||
return static_cast<c10::complex<c10::Half>>(c10::complex<float>{src});
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct static_cast_with_inter_type<c10::complex<c10::Half>, c10::Half> {
|
||||
C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex<
|
||||
c10::Half>
|
||||
apply(c10::Half src) {
|
||||
return static_cast<c10::complex<c10::Half>>(c10::complex<float>{src});
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct static_cast_with_inter_type<
|
||||
c10::complex<c10::Half>,
|
||||
c10::complex<double>> {
|
||||
C10_HOST_DEVICE __ubsan_ignore_undefined__ static inline c10::complex<
|
||||
c10::Half>
|
||||
apply(c10::complex<double> src) {
|
||||
return static_cast<c10::complex<c10::Half>>(
|
||||
static_cast<c10::complex<float>>(src));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename To, typename From>
|
||||
C10_HOST_DEVICE To convert(From f) {
|
||||
return static_cast_with_inter_type<To, From>::apply(f);
|
||||
}
|
||||
|
||||
// Define separately to avoid being inlined and prevent code-size bloat
|
||||
[[noreturn]] C10_API void report_overflow(const char* name);
|
||||
|
||||
template <typename To, typename From>
|
||||
To checked_convert(From f, const char* name) {
|
||||
// Converting to bool can't overflow so we exclude this case from checking.
|
||||
if (!std::is_same_v<To, bool> && overflows<To, From>(f)) {
|
||||
report_overflow(name);
|
||||
}
|
||||
return convert<To, From>(f);
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
C10_CLANG_DIAGNOSTIC_POP()
|
||||
|
||||
// Trigger tests for D25440771. TODO: Remove this line any time you want.
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,132 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/util/ConstexprCrc.h>
|
||||
#include <c10/util/IdWrapper.h>
|
||||
#include <c10/util/string_view.h>
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#if !defined(FBCODE_CAFFE2) && !defined(C10_NODEPRECATED)
|
||||
#define C10_TYPENAME_SUPPORTS_CONSTEXPR 1
|
||||
#define C10_TYPENAME_CONSTEXPR constexpr
|
||||
#endif
|
||||
|
||||
namespace c10::util {
|
||||
|
||||
struct type_index final : IdWrapper<type_index, uint64_t> {
|
||||
constexpr explicit type_index(uint64_t checksum) : IdWrapper(checksum) {}
|
||||
|
||||
// Allow usage in std::map / std::set
|
||||
// TODO Disallow this and rather use std::unordered_map/set everywhere
|
||||
friend constexpr bool operator<(type_index lhs, type_index rhs) noexcept {
|
||||
return lhs.underlyingId() < rhs.underlyingId();
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& stream, type_index typeId) {
|
||||
return stream << typeId.underlyingId();
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
inline constexpr c10::c10_string_view fully_qualified_type_name_impl() {
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
constexpr std::string_view fun_sig = __FUNCSIG__;
|
||||
#if defined(__NVCC__)
|
||||
constexpr std::string_view prefix =
|
||||
"c10::basic_string_view<char> c10::util::detail::fully_qualified_type_name_impl<";
|
||||
constexpr std::string_view suffix = ">()";
|
||||
#else
|
||||
constexpr std::string_view prefix =
|
||||
"class c10::basic_string_view<char> __cdecl c10::util::detail::fully_qualified_type_name_impl<";
|
||||
constexpr std::string_view suffix = ">(void)";
|
||||
#endif
|
||||
#elif defined(__clang__)
|
||||
constexpr std::string_view fun_sig = __PRETTY_FUNCTION__;
|
||||
constexpr std::string_view prefix =
|
||||
"c10::c10_string_view c10::util::detail::fully_qualified_type_name_impl() [T = ";
|
||||
constexpr std::string_view suffix = "]";
|
||||
#elif defined(__GNUC__)
|
||||
constexpr std::string_view fun_sig = __PRETTY_FUNCTION__;
|
||||
constexpr std::string_view prefix =
|
||||
"constexpr c10::c10_string_view c10::util::detail::fully_qualified_type_name_impl() [with T = ";
|
||||
constexpr std::string_view suffix =
|
||||
"; c10::c10_string_view = c10::basic_string_view<char>]";
|
||||
#endif
|
||||
#if !defined(__CUDA_ARCH__) && !defined(__CUDA_ARCH_LIST__)
|
||||
static_assert(c10::starts_with(
|
||||
static_cast<std::string_view>(fun_sig),
|
||||
static_cast<std::string_view>(prefix)));
|
||||
static_assert(c10::ends_with(
|
||||
static_cast<std::string_view>(fun_sig),
|
||||
static_cast<std::string_view>(suffix)));
|
||||
#endif
|
||||
return fun_sig.substr(
|
||||
prefix.size(), fun_sig.size() - prefix.size() - suffix.size());
|
||||
}
|
||||
|
||||
#if !defined(__CUDA_ARCH__) && !defined(__CUDA_ARCH_LIST__)
|
||||
template <typename T>
|
||||
inline constexpr uint64_t type_index_impl() {
|
||||
// Idea: __PRETTY_FUNCTION__ (or __FUNCSIG__ on msvc) contains a qualified name
|
||||
// of this function, including its template parameter, i.e. including the
|
||||
// type we want an id for. We use this name and run crc64 on it to get a type
|
||||
// id.
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
return crc64(__FUNCSIG__, sizeof(__FUNCSIG__)).checksum();
|
||||
#elif defined(__clang__)
|
||||
return crc64(__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__)).checksum();
|
||||
#elif defined(__GNUC__)
|
||||
return crc64(__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__)).checksum();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
inline constexpr type_index get_type_index() {
|
||||
#if !defined(__CUDA_ARCH__) && !defined(__CUDA_ARCH_LIST__)
|
||||
// To enforce that this is really computed at compile time, we pass the
|
||||
// type index through std::integral_constant.
|
||||
return type_index{std::integral_constant<
|
||||
uint64_t,
|
||||
detail::type_index_impl<std::decay_t<T>>()>::value};
|
||||
#else
|
||||
// There's nothing in theory preventing us from running this on device code
|
||||
// except for nvcc throwing a compiler error if we enable it.
|
||||
return (abort(), type_index(0));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(TORCH_PEDANTIC)
|
||||
// Use precomputed hashsum for std::string
|
||||
// Needed to workaround ambiguity in class name resolution
|
||||
// into __PRETTY_FUNCTION__ when abovementioned class is defined in inlined
|
||||
// namespace. In multi-ABI C++ library, `std::string` is an alias to
|
||||
// `std::__cxx11::basic_string<char>` which depending on compiler flags can be
|
||||
// resolved to `basic_string<char>` either in `std` namespace or in
|
||||
// `std::__cxx11` one (`__cxx11` is an inline namespace)
|
||||
template <>
|
||||
inline constexpr type_index get_type_index<std::string>() {
|
||||
// hashsum for std::basic_string<char>
|
||||
return type_index{4193213214807308375ULL};
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
inline constexpr std::string_view get_fully_qualified_type_name() noexcept {
|
||||
return static_cast<std::string_view>(
|
||||
detail::fully_qualified_type_name_impl<T>());
|
||||
}
|
||||
} // namespace c10::util
|
||||
|
||||
C10_DEFINE_HASH_FOR_IDWRAPPER(c10::util::type_index)
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/TypeList.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/TypeSafeSignMath.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/TypeTraits.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,19 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <c10/util/Exception.h>
|
||||
#include <c10/util/win32-headers.h>
|
||||
#include <string>
|
||||
#endif
|
||||
|
||||
namespace c10 {
|
||||
#if defined(_WIN32)
|
||||
C10_API std::wstring u8u16(const std::string& str);
|
||||
C10_API std::string u16u8(const std::wstring& wstr);
|
||||
#endif
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,145 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <c10/macros/Export.h>
|
||||
#include <c10/macros/Macros.h>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
using DeleterFnPtr = void (*)(void*);
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Does not delete anything
|
||||
C10_API 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 (C10_UNLIKELY(ctx_.get_deleter() != &deleteNothing)) {
|
||||
return false;
|
||||
}
|
||||
// seems quicker than calling the no-op deleter when we reset
|
||||
// NOLINTNEXTLINE(bugprone-unused-return-value)
|
||||
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
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,35 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <type_traits>
|
||||
|
||||
// Utility to guarantee complete unrolling of a loop where the bounds are known
|
||||
// at compile time. Various pragmas achieve similar effects, but are not as
|
||||
// portable across compilers.
|
||||
|
||||
// Example: c10::ForcedUnroll<4>{}(f); is equivalent to f(0); f(1); f(2); f(3);
|
||||
|
||||
namespace c10 {
|
||||
|
||||
template <int n>
|
||||
struct ForcedUnroll {
|
||||
template <typename Func, typename... Args>
|
||||
C10_ALWAYS_INLINE void operator()(const Func& f, Args... args) const {
|
||||
ForcedUnroll<n - 1>{}(f, args...);
|
||||
f(std::integral_constant<int, n - 1>{}, args...);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ForcedUnroll<1> {
|
||||
template <typename Func, typename... Args>
|
||||
C10_ALWAYS_INLINE void operator()(const Func& f, Args... args) const {
|
||||
f(std::integral_constant<int, 0>{}, args...);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,109 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/ScopeExit.h>
|
||||
#include <c10/util/SmallVector.h>
|
||||
|
||||
namespace c10::monitor {
|
||||
namespace detail {
|
||||
class WaitCounterImpl;
|
||||
|
||||
class WaitCounterBackendIf {
|
||||
public:
|
||||
virtual ~WaitCounterBackendIf() = default;
|
||||
|
||||
virtual intptr_t start(
|
||||
std::chrono::steady_clock::time_point now) noexcept = 0;
|
||||
virtual void stop(
|
||||
std::chrono::steady_clock::time_point now,
|
||||
intptr_t ctx) noexcept = 0;
|
||||
};
|
||||
|
||||
class WaitCounterBackendFactoryIf {
|
||||
public:
|
||||
virtual ~WaitCounterBackendFactoryIf() = default;
|
||||
|
||||
// May return nullptr.
|
||||
// In this case the counter will be ignored by the given backend.
|
||||
virtual std::unique_ptr<WaitCounterBackendIf> create(
|
||||
std::string_view key) noexcept = 0;
|
||||
};
|
||||
|
||||
C10_API void registerWaitCounterBackend(
|
||||
std::unique_ptr<WaitCounterBackendFactoryIf> /*factory*/);
|
||||
|
||||
C10_API std::vector<std::shared_ptr<WaitCounterBackendFactoryIf>>
|
||||
getRegisteredWaitCounterBackends();
|
||||
} // namespace detail
|
||||
|
||||
// A handle to a wait counter.
|
||||
class C10_API WaitCounterHandle {
|
||||
public:
|
||||
explicit WaitCounterHandle(std::string_view key);
|
||||
|
||||
class WaitGuard {
|
||||
public:
|
||||
WaitGuard(WaitGuard&& other) noexcept
|
||||
: handle_{std::exchange(other.handle_, {})},
|
||||
ctxs_{std::move(other.ctxs_)} {}
|
||||
WaitGuard(const WaitGuard&) = delete;
|
||||
WaitGuard& operator=(const WaitGuard&) = delete;
|
||||
WaitGuard& operator=(WaitGuard&&) = delete;
|
||||
|
||||
~WaitGuard() {
|
||||
stop();
|
||||
}
|
||||
|
||||
void stop() {
|
||||
if (auto handle = std::exchange(handle_, nullptr)) {
|
||||
handle->stop(ctxs_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
WaitGuard(WaitCounterHandle& handle, SmallVector<intptr_t>&& ctxs)
|
||||
: handle_{&handle}, ctxs_{std::move(ctxs)} {}
|
||||
|
||||
friend class WaitCounterHandle;
|
||||
|
||||
WaitCounterHandle* handle_;
|
||||
SmallVector<intptr_t> ctxs_;
|
||||
};
|
||||
|
||||
// Starts a waiter
|
||||
WaitGuard start();
|
||||
|
||||
private:
|
||||
// Stops the waiter. Each start() call should be matched by exactly one stop()
|
||||
// call.
|
||||
void stop(const SmallVector<intptr_t>& ctxs);
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
||||
detail::WaitCounterImpl& impl_;
|
||||
};
|
||||
} // namespace c10::monitor
|
||||
|
||||
#define STATIC_WAIT_COUNTER(_key) \
|
||||
[]() -> ::c10::monitor::WaitCounterHandle& { \
|
||||
static ::c10::monitor::WaitCounterHandle handle(#_key); \
|
||||
return handle; \
|
||||
}()
|
||||
|
||||
#define STATIC_SCOPED_WAIT_COUNTER(_name) \
|
||||
auto C10_ANONYMOUS_VARIABLE(SCOPE_GUARD) = STATIC_WAIT_COUNTER(_name).start();
|
||||
|
||||
#define WITH_WAIT_COUNTER(_name, _expr) \
|
||||
[&]() { \
|
||||
STATIC_SCOPED_WAIT_COUNTER(_name); \
|
||||
return _expr; \
|
||||
}();
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <string_view>
|
||||
|
||||
namespace c10::monitor::detail {
|
||||
|
||||
struct WaitCounterDynamicBackend {
|
||||
void* self{nullptr};
|
||||
intptr_t (*start)(void* self, int64_t nowUs){nullptr};
|
||||
void (*stop)(void* self, int64_t nowUs, intptr_t ctx){nullptr};
|
||||
void (*destroy)(void* self){nullptr};
|
||||
};
|
||||
|
||||
using WaitCounterDynamicBackendInit =
|
||||
void (*)(WaitCounterDynamicBackend*, const char* key, std::size_t keyLen);
|
||||
|
||||
// This name needs to be updated if anything in the API above is changed.
|
||||
constexpr std::string_view kWaitCounterDynamicBackendInitFn =
|
||||
"c10_monitor_wait_counter_dynamic_backend_init_v1";
|
||||
} // namespace c10::monitor::detail
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,129 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/util/Exception.h>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <numeric>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/// Sum of a list of integers; accumulates into the int64_t datatype
|
||||
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) {
|
||||
// std::accumulate infers return type from `init` type, so if the `init` type
|
||||
// is not large enough to hold the result, computation can overflow. We use
|
||||
// `int64_t` here to avoid this.
|
||||
return std::accumulate(
|
||||
container.begin(), container.end(), static_cast<int64_t>(0));
|
||||
}
|
||||
|
||||
/// Sum of integer elements referred to by iterators; accumulates into the
|
||||
/// int64_t datatype
|
||||
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) {
|
||||
// std::accumulate infers return type from `init` type, so if the `init` type
|
||||
// is not large enough to hold the result, computation can overflow. We use
|
||||
// `int64_t` here to avoid this.
|
||||
return std::accumulate(begin, end, static_cast<int64_t>(0));
|
||||
}
|
||||
|
||||
/// Product of a list of integers; accumulates into the int64_t datatype
|
||||
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) {
|
||||
// std::accumulate infers return type from `init` type, so if the `init` type
|
||||
// is not large enough to hold the result, computation can overflow. We use
|
||||
// `int64_t` here to avoid this.
|
||||
return std::accumulate(
|
||||
container.begin(),
|
||||
container.end(),
|
||||
static_cast<int64_t>(1),
|
||||
std::multiplies<>());
|
||||
}
|
||||
|
||||
/// Product of integer elements referred to by iterators; accumulates into the
|
||||
/// int64_t datatype
|
||||
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) {
|
||||
// std::accumulate infers return type from `init` type, so if the `init` type
|
||||
// is not large enough to hold the result, computation can overflow. We use
|
||||
// `int64_t` here to avoid this.
|
||||
return std::accumulate(
|
||||
begin, end, static_cast<int64_t>(1), std::multiplies<>());
|
||||
}
|
||||
|
||||
/// Return product of all dimensions starting from k
|
||||
/// Returns 1 if k>=dims.size()
|
||||
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) {
|
||||
TORCH_INTERNAL_ASSERT_DEBUG_ONLY(k >= 0);
|
||||
|
||||
if (k > static_cast<int>(dims.size())) {
|
||||
return 1;
|
||||
} else {
|
||||
auto cbegin = dims.cbegin();
|
||||
std::advance(cbegin, k);
|
||||
return multiply_integers(cbegin, dims.cend());
|
||||
}
|
||||
}
|
||||
|
||||
/// Product of all dims up to k (not including dims[k])
|
||||
/// Throws an error if k>dims.size()
|
||||
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);
|
||||
}
|
||||
|
||||
/// Product of all dims between k and l (including dims[k] and excluding
|
||||
/// dims[l]) k and l may be supplied in either order
|
||||
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
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/bit_cast.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/bits.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,83 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <complex>
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/Half.h>
|
||||
#include <torch/headeronly/util/complex.h>
|
||||
|
||||
// std functions
|
||||
//
|
||||
// The implementation of these functions also follow the design of C++20
|
||||
|
||||
namespace std {
|
||||
|
||||
template <typename T>
|
||||
constexpr T real(const c10::complex<T>& z) {
|
||||
return z.real();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr T imag(const c10::complex<T>& z) {
|
||||
return z.imag();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE T abs(const c10::complex<T>& z) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return thrust::abs(static_cast<thrust::complex<T>>(z));
|
||||
#else
|
||||
return std::abs(static_cast<std::complex<T>>(z));
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(USE_ROCM)
|
||||
#define ROCm_Bug(x)
|
||||
#else
|
||||
#define ROCm_Bug(x) x
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE T arg(const c10::complex<T>& z) {
|
||||
return ROCm_Bug(std)::atan2(std::imag(z), std::real(z));
|
||||
}
|
||||
|
||||
#undef ROCm_Bug
|
||||
|
||||
template <typename T>
|
||||
constexpr T norm(const c10::complex<T>& z) {
|
||||
return z.real() * z.real() + z.imag() * z.imag();
|
||||
}
|
||||
|
||||
// For std::conj, there are other versions of it:
|
||||
// constexpr std::complex<float> conj( float z );
|
||||
// template< class DoubleOrInteger >
|
||||
// constexpr std::complex<double> conj( DoubleOrInteger z );
|
||||
// constexpr std::complex<long double> conj( long double z );
|
||||
// These are not implemented
|
||||
// TODO(@zasdfgbnm): implement them as c10::conj
|
||||
template <typename T>
|
||||
constexpr c10::complex<T> conj(const c10::complex<T>& z) {
|
||||
return c10::complex<T>(z.real(), -z.imag());
|
||||
}
|
||||
|
||||
// Thrust does not have complex --> complex version of thrust::proj,
|
||||
// so this function is not implemented at c10 right now.
|
||||
// TODO(@zasdfgbnm): implement it by ourselves
|
||||
|
||||
// There is no c10 version of std::polar, because std::polar always
|
||||
// returns std::complex. Use c10::polar instead;
|
||||
|
||||
} // namespace std
|
||||
|
||||
#define C10_INTERNAL_INCLUDE_COMPLEX_REMAINING_H
|
||||
// math functions are included in a separate file
|
||||
#include <c10/util/complex_math.h> // IWYU pragma: keep
|
||||
// utilities for complex types
|
||||
#include <c10/util/complex_utils.h> // IWYU pragma: keep
|
||||
#undef C10_INTERNAL_INCLUDE_COMPLEX_REMAINING_H
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,446 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#if !defined(C10_INTERNAL_INCLUDE_COMPLEX_REMAINING_H)
|
||||
#error \
|
||||
"c10/util/complex_math.h is not meant to be individually included. Include c10/util/complex.h instead."
|
||||
#endif
|
||||
|
||||
namespace c10_complex_math {
|
||||
|
||||
// Exponential functions
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> exp(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::exp(static_cast<thrust::complex<T>>(x)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::exp(static_cast<std::complex<T>>(x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> log(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::log(static_cast<thrust::complex<T>>(x)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::log(static_cast<std::complex<T>>(x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> log10(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::log10(static_cast<thrust::complex<T>>(x)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::log10(static_cast<std::complex<T>>(x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> log2(const c10::complex<T>& x) {
|
||||
const c10::complex<T> log2 = c10::complex<T>(::log(2.0), 0.0);
|
||||
return c10_complex_math::log(x) / log2;
|
||||
}
|
||||
|
||||
// Power functions
|
||||
//
|
||||
#if defined(_LIBCPP_VERSION) || \
|
||||
(defined(__GLIBCXX__) && !defined(_GLIBCXX11_USE_C99_COMPLEX))
|
||||
namespace _detail {
|
||||
C10_API c10::complex<float> sqrt(const c10::complex<float>& in);
|
||||
C10_API c10::complex<double> sqrt(const c10::complex<double>& in);
|
||||
C10_API c10::complex<float> acos(const c10::complex<float>& in);
|
||||
C10_API c10::complex<double> acos(const c10::complex<double>& in);
|
||||
} // namespace _detail
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> sqrt(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::sqrt(static_cast<thrust::complex<T>>(x)));
|
||||
#elif !( \
|
||||
defined(_LIBCPP_VERSION) || \
|
||||
(defined(__GLIBCXX__) && !defined(_GLIBCXX11_USE_C99_COMPLEX)))
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::sqrt(static_cast<std::complex<T>>(x)));
|
||||
#else
|
||||
return _detail::sqrt(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> pow(
|
||||
const c10::complex<T>& x,
|
||||
const c10::complex<T>& y) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(thrust::pow(
|
||||
static_cast<thrust::complex<T>>(x), static_cast<thrust::complex<T>>(y)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(std::pow(
|
||||
static_cast<std::complex<T>>(x), static_cast<std::complex<T>>(y)));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Regression in ROCm 7.2. See https://github.com/ROCm/rocm-libraries/pull/3836.
|
||||
// Specialized version for complex<float> on AMD GPUs to use FMA-based
|
||||
// multiplication
|
||||
#if defined(__HIPCC__)
|
||||
namespace detail {
|
||||
// FMA-aware complex multiplication for float precision on AMD GPUs.
|
||||
// This prevents SLP vectorizer from breaking FMA formation, which causes
|
||||
// numerical precision loss in complex arithmetic.
|
||||
// The issue occurs when vectorizer packs scalar multiplies before backend
|
||||
// can form FMA instructions, resulting in double rounding instead of single.
|
||||
C10_HOST_DEVICE inline thrust::complex<float> complex_mul_fma(
|
||||
thrust::complex<float> a,
|
||||
thrust::complex<float> b) {
|
||||
// Complex multiplication: (a.r + a.i*i) * (b.r + b.i*i)
|
||||
// = (a.r*b.r - a.i*b.i) + (a.r*b.i + a.i*b.r)*i
|
||||
// Using __builtin_fmaf ensures FMA at source level:
|
||||
// real: a.r*b.r + (-(a.i*b.i)) = FMA(a.r, b.r, -(a.i*b.i))
|
||||
// imag: a.i*b.r + a.r*b.i = FMA(a.r, b.i, a.i*b.r)
|
||||
float real_part = __builtin_fmaf(a.real(), b.real(), -(a.imag() * b.imag()));
|
||||
float imag_part = __builtin_fmaf(a.real(), b.imag(), a.imag() * b.real());
|
||||
return thrust::complex<float>(real_part, imag_part);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <>
|
||||
C10_HOST_DEVICE inline c10::complex<float> pow(
|
||||
const c10::complex<float>& x,
|
||||
const c10::complex<float>& y) {
|
||||
auto log_x = thrust::log(static_cast<thrust::complex<float>>(x));
|
||||
auto y_log_x =
|
||||
detail::complex_mul_fma(static_cast<thrust::complex<float>>(y), log_x);
|
||||
return static_cast<c10::complex<float>>(thrust::exp(y_log_x));
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> pow(
|
||||
const c10::complex<T>& x,
|
||||
const T& y) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::pow(static_cast<thrust::complex<T>>(x), y));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::pow(static_cast<std::complex<T>>(x), y));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> pow(
|
||||
const T& x,
|
||||
const c10::complex<T>& y) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::pow(x, static_cast<thrust::complex<T>>(y)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::pow(x, static_cast<std::complex<T>>(y)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
C10_HOST_DEVICE inline c10::complex<decltype(T() * U())> pow(
|
||||
const c10::complex<T>& x,
|
||||
const c10::complex<U>& y) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(thrust::pow(
|
||||
static_cast<thrust::complex<T>>(x), static_cast<thrust::complex<T>>(y)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(std::pow(
|
||||
static_cast<std::complex<T>>(x), static_cast<std::complex<T>>(y)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
C10_HOST_DEVICE inline c10::complex<decltype(T() * U())> pow(
|
||||
const c10::complex<T>& x,
|
||||
const U& y) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::pow(static_cast<thrust::complex<T>>(x), y));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::pow(static_cast<std::complex<T>>(x), y));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
C10_HOST_DEVICE inline c10::complex<decltype(T() * U())> pow(
|
||||
const T& x,
|
||||
const c10::complex<U>& y) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::pow(x, static_cast<thrust::complex<T>>(y)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::pow(x, static_cast<std::complex<T>>(y)));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Trigonometric functions
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> sin(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::sin(static_cast<thrust::complex<T>>(x)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::sin(static_cast<std::complex<T>>(x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> cos(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::cos(static_cast<thrust::complex<T>>(x)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::cos(static_cast<std::complex<T>>(x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> tan(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::tan(static_cast<thrust::complex<T>>(x)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::tan(static_cast<std::complex<T>>(x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> asin(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::asin(static_cast<thrust::complex<T>>(x)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::asin(static_cast<std::complex<T>>(x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> acos(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::acos(static_cast<thrust::complex<T>>(x)));
|
||||
#elif !defined(_LIBCPP_VERSION)
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::acos(static_cast<std::complex<T>>(x)));
|
||||
#else
|
||||
return _detail::acos(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> atan(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::atan(static_cast<thrust::complex<T>>(x)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::atan(static_cast<std::complex<T>>(x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Hyperbolic functions
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> sinh(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::sinh(static_cast<thrust::complex<T>>(x)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::sinh(static_cast<std::complex<T>>(x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> cosh(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::cosh(static_cast<thrust::complex<T>>(x)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::cosh(static_cast<std::complex<T>>(x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> tanh(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::tanh(static_cast<thrust::complex<T>>(x)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::tanh(static_cast<std::complex<T>>(x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> asinh(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::asinh(static_cast<thrust::complex<T>>(x)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::asinh(static_cast<std::complex<T>>(x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> acosh(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::acosh(static_cast<thrust::complex<T>>(x)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::acosh(static_cast<std::complex<T>>(x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> atanh(const c10::complex<T>& x) {
|
||||
#if defined(__CUDACC__) || defined(__HIPCC__)
|
||||
return static_cast<c10::complex<T>>(
|
||||
thrust::atanh(static_cast<thrust::complex<T>>(x)));
|
||||
#else
|
||||
return static_cast<c10::complex<T>>(
|
||||
std::atanh(static_cast<std::complex<T>>(x)));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> log1p(const c10::complex<T>& z) {
|
||||
#if defined(__APPLE__) || defined(__MACOSX) || defined(__CUDACC__) || \
|
||||
defined(__HIPCC__)
|
||||
// For Mac, the new implementation yielded a high relative error. Falling back
|
||||
// to the old version for now.
|
||||
// See https://github.com/numpy/numpy/pull/22611#issuecomment-1667945354
|
||||
// For CUDA we also use this one, as thrust::log(thrust::complex) takes
|
||||
// *forever* to compile
|
||||
|
||||
// log1p(z) = log(1 + z)
|
||||
// Let's define 1 + z = r * e ^ (i * a), then we have
|
||||
// log(r * e ^ (i * a)) = log(r) + i * a
|
||||
// With z = x + iy, the term r can be written as
|
||||
// r = ((1 + x) ^ 2 + y ^ 2) ^ 0.5
|
||||
// = (1 + x ^ 2 + 2 * x + y ^ 2) ^ 0.5
|
||||
// So, log(r) is
|
||||
// log(r) = 0.5 * log(1 + x ^ 2 + 2 * x + y ^ 2)
|
||||
// = 0.5 * log1p(x * (x + 2) + y ^ 2)
|
||||
// we need to use the expression only on certain condition to avoid overflow
|
||||
// and underflow from `(x * (x + 2) + y ^ 2)`
|
||||
T x = z.real();
|
||||
T y = z.imag();
|
||||
T zabs = std::abs(z);
|
||||
T theta = std::atan2(y, x + T(1));
|
||||
if (zabs < 0.5) {
|
||||
T r = x * (T(2) + x) + y * y;
|
||||
if (r == 0) { // handle underflow
|
||||
return {x, theta};
|
||||
}
|
||||
return {T(0.5) * std::log1p(r), theta};
|
||||
} else {
|
||||
T z0 = std::hypot(x + 1, y);
|
||||
return {std::log(z0), theta};
|
||||
}
|
||||
#else
|
||||
// CPU path
|
||||
// Based on https://github.com/numpy/numpy/pull/22611#issuecomment-1667945354
|
||||
c10::complex<T> u = z + T(1);
|
||||
if (u == T(1)) {
|
||||
return z;
|
||||
} else {
|
||||
auto log_u = log(u);
|
||||
if (u - T(1) == z) {
|
||||
return log_u;
|
||||
}
|
||||
return log_u * (z / (u - T(1)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
C10_HOST_DEVICE inline c10::complex<T> expm1(const c10::complex<T>& z) {
|
||||
// expm1(z) = exp(z) - 1
|
||||
// Define z = x + i * y
|
||||
// f = e ^ (x + i * y) - 1
|
||||
// = e ^ x * e ^ (i * y) - 1
|
||||
// = (e ^ x * cos(y) - 1) + i * (e ^ x * sin(y))
|
||||
// = (e ^ x - 1) * cos(y) - (1 - cos(y)) + i * e ^ x * sin(y)
|
||||
// = expm1(x) * cos(y) - 2 * sin(y / 2) ^ 2 + i * e ^ x * sin(y)
|
||||
T x = z.real();
|
||||
T y = z.imag();
|
||||
T a = std::sin(y / 2);
|
||||
T er = std::expm1(x) * std::cos(y) - T(2) * a * a;
|
||||
T ei = std::exp(x) * std::sin(y);
|
||||
return {er, ei};
|
||||
}
|
||||
|
||||
} // namespace c10_complex_math
|
||||
|
||||
using c10_complex_math::acos;
|
||||
using c10_complex_math::acosh;
|
||||
using c10_complex_math::asin;
|
||||
using c10_complex_math::asinh;
|
||||
using c10_complex_math::atan;
|
||||
using c10_complex_math::atanh;
|
||||
using c10_complex_math::cos;
|
||||
using c10_complex_math::cosh;
|
||||
using c10_complex_math::exp;
|
||||
using c10_complex_math::expm1;
|
||||
using c10_complex_math::log;
|
||||
using c10_complex_math::log10;
|
||||
using c10_complex_math::log1p;
|
||||
using c10_complex_math::log2;
|
||||
using c10_complex_math::pow;
|
||||
using c10_complex_math::sin;
|
||||
using c10_complex_math::sinh;
|
||||
using c10_complex_math::sqrt;
|
||||
using c10_complex_math::tan;
|
||||
using c10_complex_math::tanh;
|
||||
|
||||
namespace std {
|
||||
|
||||
using c10_complex_math::acos;
|
||||
using c10_complex_math::acosh;
|
||||
using c10_complex_math::asin;
|
||||
using c10_complex_math::asinh;
|
||||
using c10_complex_math::atan;
|
||||
using c10_complex_math::atanh;
|
||||
using c10_complex_math::cos;
|
||||
using c10_complex_math::cosh;
|
||||
using c10_complex_math::exp;
|
||||
using c10_complex_math::expm1;
|
||||
using c10_complex_math::log;
|
||||
using c10_complex_math::log10;
|
||||
using c10_complex_math::log1p;
|
||||
using c10_complex_math::log2;
|
||||
using c10_complex_math::pow;
|
||||
using c10_complex_math::sin;
|
||||
using c10_complex_math::sinh;
|
||||
using c10_complex_math::sqrt;
|
||||
using c10_complex_math::tan;
|
||||
using c10_complex_math::tanh;
|
||||
|
||||
} // namespace std
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,51 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#if !defined(C10_INTERNAL_INCLUDE_COMPLEX_REMAINING_H)
|
||||
#error \
|
||||
"c10/util/complex_utils.h is not meant to be individually included. Include c10/util/complex.h instead."
|
||||
#endif
|
||||
|
||||
#include <limits>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
template <typename T>
|
||||
struct is_complex : public std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_complex<std::complex<T>> : public std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_complex<c10::complex<T>> : public std::true_type {};
|
||||
|
||||
// Extract double from std::complex<double>; is identity otherwise
|
||||
// TODO: Write in more idiomatic C++17
|
||||
template <typename T>
|
||||
struct scalar_value_type {
|
||||
using type = T;
|
||||
};
|
||||
template <typename T>
|
||||
struct scalar_value_type<std::complex<T>> {
|
||||
using type = T;
|
||||
};
|
||||
template <typename T>
|
||||
struct scalar_value_type<c10::complex<T>> {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
namespace std {
|
||||
|
||||
template <typename T>
|
||||
class numeric_limits<c10::complex<T>> : public numeric_limits<T> {};
|
||||
|
||||
template <typename T>
|
||||
bool isnan(const c10::complex<T>& v) {
|
||||
return std::isnan(v.real()) || std::isnan(v.imag());
|
||||
}
|
||||
|
||||
} // namespace std
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,32 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/util/BFloat16.h>
|
||||
#include <c10/util/Half.h>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// Note: Explicit implementation of copysign for Half and BFloat16
|
||||
// is needed to workaround g++-7/8 crash on aarch64, but also makes
|
||||
// copysign faster for the half-precision types
|
||||
template <typename T, typename U>
|
||||
inline auto copysign(const T& a, const U& b) {
|
||||
return std::copysign(a, b);
|
||||
}
|
||||
|
||||
// Implement copysign for half precision floats using bit ops
|
||||
// Sign is the most significant bit for both half and bfloat16 types
|
||||
inline c10::Half copysign(c10::Half a, c10::Half b) {
|
||||
return c10::Half((a.x & 0x7fff) | (b.x & 0x8000), c10::Half::from_bits());
|
||||
}
|
||||
|
||||
inline c10::BFloat16 copysign(c10::BFloat16 a, c10::BFloat16 b) {
|
||||
return c10::BFloat16(
|
||||
(a.x & 0x7fff) | (b.x & 0x8000), c10::BFloat16::from_bits());
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,36 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Export.h>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
namespace c10::utils {
|
||||
|
||||
// Set an environment variable.
|
||||
C10_API void set_env(
|
||||
const char* name,
|
||||
const char* value,
|
||||
bool overwrite = true);
|
||||
|
||||
// Checks an environment variable is set.
|
||||
C10_API bool has_env(const char* name) noexcept;
|
||||
|
||||
// Reads an environment variable and returns
|
||||
// - std::optional<true>, if set equal to "1"
|
||||
// - std::optional<false>, if set equal to "0"
|
||||
// - nullopt, otherwise
|
||||
//
|
||||
// NB:
|
||||
// Issues a warning if the value of the environment variable is not 0 or 1.
|
||||
C10_API std::optional<bool> check_env(const char* name);
|
||||
|
||||
// Reads the value of an environment variable if it is set.
|
||||
// However, check_env should be used if the value is assumed to be a flag.
|
||||
C10_API std::optional<std::string> get_env(const char* name) noexcept;
|
||||
|
||||
} // namespace c10::utils
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,16 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Export.h>
|
||||
#include <string>
|
||||
|
||||
namespace c10::utils {
|
||||
|
||||
// Get an error string in the thread-safe way.
|
||||
C10_API std::string str_error(int errnum);
|
||||
|
||||
} // namespace c10::utils
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/floating_point_utils.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,118 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/TypeSafeSignMath.h>
|
||||
#include <cmath>
|
||||
|
||||
#if defined(__CUDA_ARCH__) || defined(__HIPCC__)
|
||||
#if defined(__CUDA_ARCH__)
|
||||
#include <c10/cuda/CUDAMathCompat.h>
|
||||
#elif defined(__HIPCC__)
|
||||
#include <c10/hip/HIPMathCompat.h>
|
||||
#endif
|
||||
#define C10_COMPAT_COPYSIGN c10::cuda::compat::copysign
|
||||
#else
|
||||
#include <c10/util/copysign.h>
|
||||
#define C10_COMPAT_COPYSIGN c10::copysign
|
||||
#endif
|
||||
|
||||
// The functions in this file should be header-only as it is used under
|
||||
// ABI-compatibility mode.
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// NOTE: [Floor Division in Python]
|
||||
// Python's __floordiv__ operator is more complicated than just floor(a / b).
|
||||
// It aims to maintain the property: a == (a // b) * b + remainder(a, b)
|
||||
// which can otherwise fail due to rounding errors in the remainder.
|
||||
// So, instead it is calculated as: a // b = (a - remainder(a, b)) / b
|
||||
// With some additional fix-ups added to the result.
|
||||
//
|
||||
// For reference, see CPython's implementation:
|
||||
// https://github.com/python/cpython/blob/ace008c531dd685a30c1dd68f9b5ba35f20171cf/Objects/floatobject.c#L636
|
||||
|
||||
template <typename scalar_t>
|
||||
inline C10_HOST_DEVICE scalar_t div_floor_floating(scalar_t a, scalar_t b)
|
||||
__ubsan_ignore_float_divide_by_zero__ {
|
||||
if (C10_UNLIKELY(b == 0)) {
|
||||
// Divide by zero: return standard IEEE result
|
||||
return a / b;
|
||||
}
|
||||
|
||||
auto mod = std::fmod(a, b);
|
||||
auto div = (a - mod) / b;
|
||||
if ((mod != 0) && (b < 0) != (mod < 0)) {
|
||||
div -= scalar_t(1);
|
||||
}
|
||||
|
||||
scalar_t floordiv;
|
||||
if (div != 0) {
|
||||
floordiv = std::floor(div);
|
||||
if (div - floordiv > scalar_t(0.5)) {
|
||||
floordiv += scalar_t(1.0);
|
||||
}
|
||||
} else {
|
||||
floordiv = C10_COMPAT_COPYSIGN(scalar_t(0), a / b);
|
||||
}
|
||||
return floordiv;
|
||||
}
|
||||
|
||||
template <typename scalar_t>
|
||||
inline C10_HOST_DEVICE scalar_t div_floor_integer(scalar_t a, scalar_t b) {
|
||||
if (C10_UNLIKELY(b == 0)) {
|
||||
return scalar_t(0);
|
||||
}
|
||||
|
||||
if (C10_UNLIKELY(
|
||||
std::is_signed<scalar_t>::value &&
|
||||
a == std::numeric_limits<scalar_t>::min() && b == scalar_t(-1))) {
|
||||
return a;
|
||||
}
|
||||
|
||||
if (c10::signs_differ(a, b)) {
|
||||
// Subtracts one from the results of truncation division if the
|
||||
// divisor and dividend have different sign(bit)s and the remainder of
|
||||
// the division is nonzero
|
||||
const auto quot = a / b;
|
||||
const auto rem = a % b;
|
||||
return rem ? quot - 1 : quot;
|
||||
}
|
||||
return a / b;
|
||||
}
|
||||
|
||||
template <
|
||||
typename scalar_t,
|
||||
std::enable_if_t<std::is_floating_point_v<scalar_t>, int> = 0>
|
||||
inline C10_HOST_DEVICE scalar_t div_mod(scalar_t a, scalar_t b)
|
||||
__ubsan_ignore_float_divide_by_zero__ {
|
||||
if (C10_UNLIKELY(b == 0)) {
|
||||
// Divide by zero: return standard IEEE result
|
||||
return std::fmod(a, b);
|
||||
}
|
||||
|
||||
auto mod = std::fmod(a, b);
|
||||
if (mod == 0) {
|
||||
mod = C10_COMPAT_COPYSIGN(scalar_t(0), b);
|
||||
} else if ((b < 0) != (mod < 0)) {
|
||||
mod += b;
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
template <
|
||||
typename scalar_t,
|
||||
std::enable_if_t<std::is_integral_v<scalar_t>, int> = 0>
|
||||
inline C10_HOST_DEVICE scalar_t div_mod(scalar_t a, scalar_t b) {
|
||||
auto mod = a % b;
|
||||
if (mod != 0 && (b < 0) != (mod < 0)) {
|
||||
mod += b;
|
||||
}
|
||||
return mod;
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,384 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/util/Exception.h>
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <ios>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <c10/util/ArrayRef.h>
|
||||
#include <c10/util/complex.h>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// NOTE: hash_combine and SHA1 hashing is based on implementation from Boost
|
||||
//
|
||||
// Boost Software License - Version 1.0 - August 17th, 2003
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person or organization
|
||||
// obtaining a copy of the software and accompanying documentation covered by
|
||||
// this license (the "Software") to use, reproduce, display, distribute,
|
||||
// execute, and transmit the Software, and to prepare derivative works of the
|
||||
// Software, and to permit third-parties to whom the Software is furnished to
|
||||
// do so, all subject to the following:
|
||||
//
|
||||
// The copyright notices in the Software and this entire statement, including
|
||||
// the above license grant, this restriction and the following disclaimer,
|
||||
// must be included in all copies of the Software, in whole or in part, and
|
||||
// all derivative works of the Software, unless such copies or derivative
|
||||
// works are solely in the form of machine-executable object code generated by
|
||||
// a source language processor.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
inline size_t hash_combine(size_t seed, size_t value) {
|
||||
return seed ^ (value + 0x9e3779b9 + (seed << 6u) + (seed >> 2u));
|
||||
}
|
||||
|
||||
// Creates the SHA1 hash of a string. A 160-bit hash.
|
||||
// Based on the implementation in Boost (see notice above).
|
||||
// Note that SHA1 hashes are no longer considered cryptographically
|
||||
// secure, but are the standard hash for generating unique ids.
|
||||
// Usage:
|
||||
// // Let 'code' be a std::string
|
||||
// c10::sha1 sha1_hash{code};
|
||||
// const auto hash_code = sha1_hash.str();
|
||||
// TODO: Compare vs OpenSSL and/or CryptoPP implementations
|
||||
struct sha1 {
|
||||
typedef unsigned int(digest_type)[5];
|
||||
|
||||
sha1(const std::string& s = "") {
|
||||
if (!s.empty()) {
|
||||
reset();
|
||||
process_bytes(s.c_str(), s.size());
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
h_[0] = 0x67452301;
|
||||
h_[1] = 0xEFCDAB89;
|
||||
h_[2] = 0x98BADCFE;
|
||||
h_[3] = 0x10325476;
|
||||
h_[4] = 0xC3D2E1F0;
|
||||
|
||||
block_byte_index_ = 0;
|
||||
bit_count_low = 0;
|
||||
bit_count_high = 0;
|
||||
}
|
||||
|
||||
std::string str() {
|
||||
unsigned int digest[5];
|
||||
get_digest(digest);
|
||||
|
||||
std::ostringstream buf;
|
||||
for (unsigned int i : digest) {
|
||||
buf << std::hex << std::setfill('0') << std::setw(8) << i;
|
||||
}
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int left_rotate(unsigned int x, std::size_t n) {
|
||||
return (x << n) ^ (x >> (32 - n));
|
||||
}
|
||||
|
||||
void process_block_impl() {
|
||||
unsigned int w[80];
|
||||
|
||||
for (std::size_t i = 0; i < 16; ++i) {
|
||||
w[i] = (block_[i * 4 + 0] << 24);
|
||||
w[i] |= (block_[i * 4 + 1] << 16);
|
||||
w[i] |= (block_[i * 4 + 2] << 8);
|
||||
w[i] |= (block_[i * 4 + 3]);
|
||||
}
|
||||
|
||||
for (std::size_t i = 16; i < 80; ++i) {
|
||||
w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
|
||||
}
|
||||
|
||||
unsigned int a = h_[0];
|
||||
unsigned int b = h_[1];
|
||||
unsigned int c = h_[2];
|
||||
unsigned int d = h_[3];
|
||||
unsigned int e = h_[4];
|
||||
|
||||
for (std::size_t i = 0; i < 80; ++i) {
|
||||
unsigned int f = 0;
|
||||
unsigned int k = 0;
|
||||
|
||||
if (i < 20) {
|
||||
f = (b & c) | (~b & d);
|
||||
k = 0x5A827999;
|
||||
} else if (i < 40) {
|
||||
f = b ^ c ^ d;
|
||||
k = 0x6ED9EBA1;
|
||||
} else if (i < 60) {
|
||||
f = (b & c) | (b & d) | (c & d);
|
||||
k = 0x8F1BBCDC;
|
||||
} else {
|
||||
f = b ^ c ^ d;
|
||||
k = 0xCA62C1D6;
|
||||
}
|
||||
|
||||
unsigned temp = left_rotate(a, 5) + f + e + k + w[i];
|
||||
e = d;
|
||||
d = c;
|
||||
c = left_rotate(b, 30);
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
h_[0] += a;
|
||||
h_[1] += b;
|
||||
h_[2] += c;
|
||||
h_[3] += d;
|
||||
h_[4] += e;
|
||||
}
|
||||
|
||||
void process_byte_impl(unsigned char byte) {
|
||||
block_[block_byte_index_++] = byte;
|
||||
|
||||
if (block_byte_index_ == 64) {
|
||||
block_byte_index_ = 0;
|
||||
process_block_impl();
|
||||
}
|
||||
}
|
||||
|
||||
void process_byte(unsigned char byte) {
|
||||
process_byte_impl(byte);
|
||||
|
||||
// size_t max value = 0xFFFFFFFF
|
||||
// if (bit_count_low + 8 >= 0x100000000) { // would overflow
|
||||
// if (bit_count_low >= 0x100000000-8) {
|
||||
if (bit_count_low < 0xFFFFFFF8) {
|
||||
bit_count_low += 8;
|
||||
} else {
|
||||
bit_count_low = 0;
|
||||
|
||||
if (bit_count_high <= 0xFFFFFFFE) {
|
||||
++bit_count_high;
|
||||
} else {
|
||||
TORCH_CHECK(false, "sha1 too many bytes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void process_block(void const* bytes_begin, void const* bytes_end) {
|
||||
unsigned char const* begin = static_cast<unsigned char const*>(bytes_begin);
|
||||
unsigned char const* end = static_cast<unsigned char const*>(bytes_end);
|
||||
for (; begin != end; ++begin) {
|
||||
process_byte(*begin);
|
||||
}
|
||||
}
|
||||
|
||||
void process_bytes(void const* buffer, std::size_t byte_count) {
|
||||
unsigned char const* b = static_cast<unsigned char const*>(buffer);
|
||||
process_block(b, b + byte_count);
|
||||
}
|
||||
|
||||
void get_digest(digest_type& digest) {
|
||||
// append the bit '1' to the message
|
||||
process_byte_impl(0x80);
|
||||
|
||||
// append k bits '0', where k is the minimum number >= 0
|
||||
// such that the resulting message length is congruent to 56 (mod 64)
|
||||
// check if there is enough space for padding and bit_count
|
||||
if (block_byte_index_ > 56) {
|
||||
// finish this block
|
||||
while (block_byte_index_ != 0) {
|
||||
process_byte_impl(0);
|
||||
}
|
||||
|
||||
// one more block
|
||||
while (block_byte_index_ < 56) {
|
||||
process_byte_impl(0);
|
||||
}
|
||||
} else {
|
||||
while (block_byte_index_ < 56) {
|
||||
process_byte_impl(0);
|
||||
}
|
||||
}
|
||||
|
||||
// append length of message (before pre-processing)
|
||||
// as a 64-bit big-endian integer
|
||||
process_byte_impl(
|
||||
static_cast<unsigned char>((bit_count_high >> 24) & 0xFF));
|
||||
process_byte_impl(
|
||||
static_cast<unsigned char>((bit_count_high >> 16) & 0xFF));
|
||||
process_byte_impl(static_cast<unsigned char>((bit_count_high >> 8) & 0xFF));
|
||||
process_byte_impl(static_cast<unsigned char>((bit_count_high) & 0xFF));
|
||||
process_byte_impl(static_cast<unsigned char>((bit_count_low >> 24) & 0xFF));
|
||||
process_byte_impl(static_cast<unsigned char>((bit_count_low >> 16) & 0xFF));
|
||||
process_byte_impl(static_cast<unsigned char>((bit_count_low >> 8) & 0xFF));
|
||||
process_byte_impl(static_cast<unsigned char>((bit_count_low) & 0xFF));
|
||||
|
||||
// get final digest
|
||||
digest[0] = h_[0];
|
||||
digest[1] = h_[1];
|
||||
digest[2] = h_[2];
|
||||
digest[3] = h_[3];
|
||||
digest[4] = h_[4];
|
||||
}
|
||||
|
||||
unsigned int h_[5]{};
|
||||
unsigned char block_[64]{};
|
||||
std::size_t block_byte_index_{};
|
||||
std::size_t bit_count_low{};
|
||||
std::size_t bit_count_high{};
|
||||
};
|
||||
|
||||
constexpr uint64_t twang_mix64(uint64_t key) noexcept {
|
||||
key = (~key) + (key << 21); // key *= (1 << 21) - 1; key -= 1;
|
||||
key = key ^ (key >> 24);
|
||||
key = key + (key << 3) + (key << 8); // key *= 1 + (1 << 3) + (1 << 8)
|
||||
key = key ^ (key >> 14);
|
||||
key = key + (key << 2) + (key << 4); // key *= 1 + (1 << 2) + (1 << 4)
|
||||
key = key ^ (key >> 28);
|
||||
key = key + (key << 31); // key *= 1 + (1 << 31)
|
||||
return key;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// c10::hash implementation
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace _hash_detail {
|
||||
|
||||
// Use template argument deduction to shorten calls to c10::hash
|
||||
template <typename T>
|
||||
size_t simple_get_hash(const T& o);
|
||||
|
||||
template <typename T, typename V>
|
||||
using type_if_not_enum = std::enable_if_t<!std::is_enum_v<T>, V>;
|
||||
|
||||
// Use SFINAE to dispatch to std::hash if possible, cast enum types to int
|
||||
// automatically, and fall back to T::hash otherwise. NOTE: C++14 added support
|
||||
// for hashing enum types to the standard, and some compilers implement it even
|
||||
// when C++14 flags aren't specified. This is why we have to disable this
|
||||
// overload if T is an enum type (and use the one below in this case).
|
||||
template <typename T>
|
||||
auto dispatch_hash(const T& o)
|
||||
-> decltype(std::hash<T>()(o), type_if_not_enum<T, size_t>()) {
|
||||
return std::hash<T>()(o);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_enum_v<T>, size_t> dispatch_hash(const T& o) {
|
||||
using R = std::underlying_type_t<T>;
|
||||
return std::hash<R>()(static_cast<R>(o));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto dispatch_hash(const T& o) -> decltype(T::hash(o), size_t()) {
|
||||
return T::hash(o);
|
||||
}
|
||||
|
||||
} // namespace _hash_detail
|
||||
|
||||
// Hasher struct
|
||||
template <typename T>
|
||||
struct hash {
|
||||
size_t operator()(const T& o) const {
|
||||
return _hash_detail::dispatch_hash(o);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for std::tuple
|
||||
template <typename... Types>
|
||||
struct hash<std::tuple<Types...>> {
|
||||
template <size_t idx, typename... Ts>
|
||||
struct tuple_hash {
|
||||
size_t operator()(const std::tuple<Ts...>& t) const {
|
||||
return hash_combine(
|
||||
_hash_detail::simple_get_hash(std::get<idx>(t)),
|
||||
tuple_hash<idx - 1, Ts...>()(t));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct tuple_hash<0, Ts...> {
|
||||
size_t operator()(const std::tuple<Ts...>& t) const {
|
||||
return _hash_detail::simple_get_hash(std::get<0>(t));
|
||||
}
|
||||
};
|
||||
|
||||
size_t operator()(const std::tuple<Types...>& t) const {
|
||||
return tuple_hash<sizeof...(Types) - 1, Types...>()(t);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct hash<std::pair<T1, T2>> {
|
||||
size_t operator()(const std::pair<T1, T2>& pair) const {
|
||||
std::tuple<T1, T2> tuple = std::make_tuple(pair.first, pair.second);
|
||||
return _hash_detail::simple_get_hash(tuple);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct hash<c10::ArrayRef<T>> {
|
||||
size_t operator()(c10::ArrayRef<T> v) const {
|
||||
size_t seed = 0;
|
||||
for (const auto& elem : v) {
|
||||
seed = hash_combine(seed, _hash_detail::simple_get_hash(elem));
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for std::vector
|
||||
template <typename T>
|
||||
struct hash<std::vector<T>> {
|
||||
size_t operator()(const std::vector<T>& v) const {
|
||||
return hash<c10::ArrayRef<T>>()(v);
|
||||
}
|
||||
};
|
||||
|
||||
namespace _hash_detail {
|
||||
|
||||
template <typename T>
|
||||
size_t simple_get_hash(const T& o) {
|
||||
return c10::hash<T>()(o);
|
||||
}
|
||||
|
||||
} // namespace _hash_detail
|
||||
|
||||
// Use this function to actually hash multiple things in one line.
|
||||
// Dispatches to c10::hash, so it can hash containers.
|
||||
// Example:
|
||||
//
|
||||
// static size_t hash(const MyStruct& s) {
|
||||
// return get_hash(s.member1, s.member2, s.member3);
|
||||
// }
|
||||
template <typename... Types>
|
||||
size_t get_hash(const Types&... args) {
|
||||
return c10::hash<decltype(std::tie(args...))>()(std::tie(args...));
|
||||
}
|
||||
|
||||
// Specialization for c10::complex
|
||||
template <typename T>
|
||||
struct hash<c10::complex<T>> {
|
||||
size_t operator()(const c10::complex<T>& c) const {
|
||||
return get_hash(c.real(), c.imag());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,403 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
// This file is based on the uint128 implementation of protobuf at
|
||||
// https://github.com/protocolbuffers/protobuf/blob/1e88936fce10cf773cb72b44c6a7f48b38c7578b/src/google/protobuf/stubs/int128.h
|
||||
//
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Export.h>
|
||||
#include <cstdint>
|
||||
#include <iosfwd>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
struct uint128_pod;
|
||||
|
||||
// TODO(xiaofeng): Define GOOGLE_PROTOBUF_HAS_CONSTEXPR when constexpr is
|
||||
// available.
|
||||
#ifdef GOOGLE_PROTOBUF_HAS_CONSTEXPR
|
||||
#define UINT128_CONSTEXPR constexpr
|
||||
#else
|
||||
#define UINT128_CONSTEXPR
|
||||
#endif
|
||||
|
||||
class uint128;
|
||||
inline uint128& operator<<=(uint128& self, int amount);
|
||||
|
||||
// An unsigned 128-bit integer type. Thread-compatible.
|
||||
class C10_API uint128 {
|
||||
public:
|
||||
UINT128_CONSTEXPR uint128(); // Sets to 0, but don't trust on this behavior.
|
||||
UINT128_CONSTEXPR uint128(uint64_t top, uint64_t bottom);
|
||||
#ifndef SWIG
|
||||
UINT128_CONSTEXPR uint128(int bottom);
|
||||
UINT128_CONSTEXPR uint128(uint32_t bottom); // Top 96 bits = 0
|
||||
#endif
|
||||
UINT128_CONSTEXPR uint128(uint64_t bottom); // hi_ = 0
|
||||
UINT128_CONSTEXPR uint128(const uint128_pod& val);
|
||||
|
||||
// Trivial copy constructor, assignment operator and destructor.
|
||||
|
||||
void Initialize(uint64_t top, uint64_t bottom);
|
||||
|
||||
// Arithmetic operators.
|
||||
uint128& operator+=(const uint128& b);
|
||||
uint128& operator-=(const uint128& b);
|
||||
uint128& operator*=(const uint128& b);
|
||||
// Long division/modulo for uint128.
|
||||
uint128& operator/=(const uint128& b);
|
||||
uint128& operator%=(const uint128& b);
|
||||
uint128 operator++(int);
|
||||
uint128 operator--(int);
|
||||
// Make msvc happy with using operator<<= from DivModImpl
|
||||
// which is a static function, and linker complained about missing
|
||||
// static version of this overload
|
||||
friend uint128& operator<<=(uint128& /*self*/, int /*amount*/);
|
||||
uint128& operator>>=(int /*amount*/);
|
||||
uint128& operator&=(const uint128& b);
|
||||
uint128& operator|=(const uint128& b);
|
||||
uint128& operator^=(const uint128& b);
|
||||
uint128& operator++();
|
||||
uint128& operator--();
|
||||
|
||||
friend uint64_t Uint128Low64(const uint128& v);
|
||||
friend uint64_t Uint128High64(const uint128& v);
|
||||
|
||||
// We add "std::" to avoid including all of port.h.
|
||||
C10_API friend std::ostream& operator<<(std::ostream& o, const uint128& b);
|
||||
|
||||
private:
|
||||
static void DivModImpl(
|
||||
uint128 dividend,
|
||||
uint128 divisor,
|
||||
uint128* quotient_ret,
|
||||
uint128* remainder_ret);
|
||||
|
||||
// Little-endian memory order optimizations can benefit from
|
||||
// having lo_ first, hi_ last.
|
||||
// See util/endian/endian.h and Load128/Store128 for storing a uint128.
|
||||
uint64_t lo_;
|
||||
uint64_t hi_;
|
||||
|
||||
// Not implemented, just declared for catching automatic type conversions.
|
||||
uint128(uint8_t);
|
||||
uint128(uint16_t);
|
||||
uint128(float v);
|
||||
uint128(double v);
|
||||
};
|
||||
|
||||
// This is a POD form of uint128 which can be used for static variables which
|
||||
// need to be operated on as uint128.
|
||||
struct uint128_pod {
|
||||
// Note: The ordering of fields is different than 'class uint128' but the
|
||||
// same as its 2-arg constructor. This enables more obvious initialization
|
||||
// of static instances, which is the primary reason for this struct in the
|
||||
// first place. This does not seem to defeat any optimizations wrt
|
||||
// operations involving this struct.
|
||||
uint64_t hi;
|
||||
uint64_t lo;
|
||||
};
|
||||
|
||||
C10_API extern const uint128_pod kuint128max;
|
||||
|
||||
// allow uint128 to be logged
|
||||
C10_API extern std::ostream& operator<<(std::ostream& o, const uint128& b);
|
||||
|
||||
// Methods to access low and high pieces of 128-bit value.
|
||||
// Defined externally from uint128 to facilitate conversion
|
||||
// to native 128-bit types when compilers support them.
|
||||
inline uint64_t Uint128Low64(const uint128& v) {
|
||||
return v.lo_;
|
||||
}
|
||||
inline uint64_t Uint128High64(const uint128& v) {
|
||||
return v.hi_;
|
||||
}
|
||||
|
||||
// TODO: perhaps it would be nice to have int128, a signed 128-bit type?
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Implementation details follow
|
||||
// --------------------------------------------------------------------------
|
||||
inline bool operator==(const uint128& lhs, const uint128& rhs) {
|
||||
return (
|
||||
Uint128Low64(lhs) == Uint128Low64(rhs) &&
|
||||
Uint128High64(lhs) == Uint128High64(rhs));
|
||||
}
|
||||
inline bool operator!=(const uint128& lhs, const uint128& rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
inline UINT128_CONSTEXPR uint128::uint128() : lo_(0), hi_(0) {}
|
||||
inline UINT128_CONSTEXPR uint128::uint128(uint64_t top, uint64_t bottom)
|
||||
: lo_(bottom), hi_(top) {}
|
||||
inline UINT128_CONSTEXPR uint128::uint128(const uint128_pod& v)
|
||||
: lo_(v.lo), hi_(v.hi) {}
|
||||
inline UINT128_CONSTEXPR uint128::uint128(uint64_t bottom)
|
||||
: lo_(bottom), hi_(0) {}
|
||||
#ifndef SWIG
|
||||
inline UINT128_CONSTEXPR uint128::uint128(uint32_t bottom)
|
||||
: lo_(bottom), hi_(0) {}
|
||||
inline UINT128_CONSTEXPR uint128::uint128(int bottom)
|
||||
: lo_(bottom), hi_(static_cast<int64_t>((bottom < 0) ? -1 : 0)) {}
|
||||
#endif
|
||||
|
||||
#undef UINT128_CONSTEXPR
|
||||
|
||||
inline void uint128::Initialize(uint64_t top, uint64_t bottom) {
|
||||
hi_ = top;
|
||||
lo_ = bottom;
|
||||
}
|
||||
|
||||
// Comparison operators.
|
||||
|
||||
#define CMP128(op) \
|
||||
inline bool operator op(const uint128& lhs, const uint128& rhs) { \
|
||||
return (Uint128High64(lhs) == Uint128High64(rhs)) \
|
||||
? (Uint128Low64(lhs) op Uint128Low64(rhs)) \
|
||||
: (Uint128High64(lhs) op Uint128High64(rhs)); \
|
||||
}
|
||||
|
||||
CMP128(<)
|
||||
CMP128(>)
|
||||
CMP128(>=)
|
||||
CMP128(<=)
|
||||
|
||||
#undef CMP128
|
||||
|
||||
// Unary operators
|
||||
|
||||
inline uint128 operator-(const uint128& val) {
|
||||
const uint64_t hi_flip = ~Uint128High64(val);
|
||||
const uint64_t lo_flip = ~Uint128Low64(val);
|
||||
const uint64_t lo_add = lo_flip + 1;
|
||||
if (lo_add < lo_flip) {
|
||||
return uint128(hi_flip + 1, lo_add);
|
||||
}
|
||||
return uint128(hi_flip, lo_add);
|
||||
}
|
||||
|
||||
inline bool operator!(const uint128& val) {
|
||||
return !Uint128High64(val) && !Uint128Low64(val);
|
||||
}
|
||||
|
||||
// Logical operators.
|
||||
|
||||
inline uint128 operator~(const uint128& val) {
|
||||
return uint128(~Uint128High64(val), ~Uint128Low64(val));
|
||||
}
|
||||
|
||||
#define LOGIC128(op) \
|
||||
inline uint128 operator op(const uint128& lhs, const uint128& rhs) { \
|
||||
return uint128( \
|
||||
Uint128High64(lhs) op Uint128High64(rhs), \
|
||||
Uint128Low64(lhs) op Uint128Low64(rhs)); \
|
||||
}
|
||||
|
||||
LOGIC128(|)
|
||||
LOGIC128(&)
|
||||
LOGIC128(^)
|
||||
|
||||
#undef LOGIC128
|
||||
|
||||
#define LOGICASSIGN128(op) \
|
||||
inline uint128& uint128::operator op(const uint128 & other) { \
|
||||
hi_ op other.hi_; \
|
||||
lo_ op other.lo_; \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
LOGICASSIGN128(|=)
|
||||
LOGICASSIGN128(&=)
|
||||
LOGICASSIGN128(^=)
|
||||
|
||||
#undef LOGICASSIGN128
|
||||
|
||||
// Shift operators.
|
||||
|
||||
inline uint128 operator<<(const uint128& val, int amount) {
|
||||
// uint64_t shifts of >= 64 are undefined, so we will need some
|
||||
// special-casing.
|
||||
if (amount < 64) {
|
||||
if (amount == 0) {
|
||||
return val;
|
||||
}
|
||||
uint64_t new_hi =
|
||||
(Uint128High64(val) << amount) | (Uint128Low64(val) >> (64 - amount));
|
||||
uint64_t new_lo = Uint128Low64(val) << amount;
|
||||
return uint128(new_hi, new_lo);
|
||||
} else if (amount < 128) {
|
||||
return uint128(Uint128Low64(val) << (amount - 64), 0);
|
||||
} else {
|
||||
return uint128(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
inline uint128 operator>>(const uint128& val, int amount) {
|
||||
// uint64_t shifts of >= 64 are undefined, so we will need some
|
||||
// special-casing.
|
||||
if (amount < 64) {
|
||||
if (amount == 0) {
|
||||
return val;
|
||||
}
|
||||
uint64_t new_hi = Uint128High64(val) >> amount;
|
||||
uint64_t new_lo =
|
||||
(Uint128Low64(val) >> amount) | (Uint128High64(val) << (64 - amount));
|
||||
return uint128(new_hi, new_lo);
|
||||
} else if (amount < 128) {
|
||||
return uint128(0, Uint128High64(val) >> (amount - 64));
|
||||
} else {
|
||||
return uint128(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
inline uint128& operator<<=(uint128& self, int amount) {
|
||||
// uint64_t shifts of >= 64 are undefined, so we will need some
|
||||
// special-casing.
|
||||
if (amount < 64) {
|
||||
if (amount != 0) {
|
||||
self.hi_ = (self.hi_ << amount) | (self.lo_ >> (64 - amount));
|
||||
self.lo_ = self.lo_ << amount;
|
||||
}
|
||||
} else if (amount < 128) {
|
||||
self.hi_ = self.lo_ << (amount - 64);
|
||||
self.lo_ = 0;
|
||||
} else {
|
||||
self.hi_ = 0;
|
||||
self.lo_ = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
inline uint128& uint128::operator>>=(int amount) {
|
||||
// uint64_t shifts of >= 64 are undefined, so we will need some
|
||||
// special-casing.
|
||||
if (amount < 64) {
|
||||
if (amount != 0) {
|
||||
lo_ = (lo_ >> amount) | (hi_ << (64 - amount));
|
||||
hi_ = hi_ >> amount;
|
||||
}
|
||||
} else if (amount < 128) {
|
||||
lo_ = hi_ >> (amount - 64);
|
||||
hi_ = 0;
|
||||
} else {
|
||||
lo_ = 0;
|
||||
hi_ = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128 operator+(const uint128& lhs, const uint128& rhs) {
|
||||
return uint128(lhs) += rhs;
|
||||
}
|
||||
|
||||
inline uint128 operator-(const uint128& lhs, const uint128& rhs) {
|
||||
return uint128(lhs) -= rhs;
|
||||
}
|
||||
|
||||
inline uint128 operator*(const uint128& lhs, const uint128& rhs) {
|
||||
return uint128(lhs) *= rhs;
|
||||
}
|
||||
|
||||
inline uint128 operator/(const uint128& lhs, const uint128& rhs) {
|
||||
return uint128(lhs) /= rhs;
|
||||
}
|
||||
|
||||
inline uint128 operator%(const uint128& lhs, const uint128& rhs) {
|
||||
return uint128(lhs) %= rhs;
|
||||
}
|
||||
|
||||
inline uint128& uint128::operator+=(const uint128& b) {
|
||||
hi_ += b.hi_;
|
||||
uint64_t lolo = lo_ + b.lo_;
|
||||
if (lolo < lo_)
|
||||
++hi_;
|
||||
lo_ = lolo;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128& uint128::operator-=(const uint128& b) {
|
||||
hi_ -= b.hi_;
|
||||
if (b.lo_ > lo_)
|
||||
--hi_;
|
||||
lo_ -= b.lo_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128& uint128::operator*=(const uint128& b) {
|
||||
uint64_t a96 = hi_ >> 32;
|
||||
uint64_t a64 = hi_ & 0xffffffffu;
|
||||
uint64_t a32 = lo_ >> 32;
|
||||
uint64_t a00 = lo_ & 0xffffffffu;
|
||||
uint64_t b96 = b.hi_ >> 32;
|
||||
uint64_t b64 = b.hi_ & 0xffffffffu;
|
||||
uint64_t b32 = b.lo_ >> 32;
|
||||
uint64_t b00 = b.lo_ & 0xffffffffu;
|
||||
// multiply [a96 .. a00] x [b96 .. b00]
|
||||
// terms higher than c96 disappear off the high side
|
||||
// terms c96 and c64 are safe to ignore carry bit
|
||||
uint64_t c96 = a96 * b00 + a64 * b32 + a32 * b64 + a00 * b96;
|
||||
uint64_t c64 = a64 * b00 + a32 * b32 + a00 * b64;
|
||||
this->hi_ = (c96 << 32) + c64;
|
||||
this->lo_ = 0;
|
||||
// add terms after this one at a time to capture carry
|
||||
*this += uint128(a32 * b00) << 32;
|
||||
*this += uint128(a00 * b32) << 32;
|
||||
*this += a00 * b00;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128 uint128::operator++(int) {
|
||||
uint128 tmp(*this);
|
||||
*this += 1;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline uint128 uint128::operator--(int) {
|
||||
uint128 tmp(*this);
|
||||
*this -= 1;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
inline uint128& uint128::operator++() {
|
||||
*this += 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline uint128& uint128::operator--() {
|
||||
*this -= 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,128 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/util/TypeSafeSignMath.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <
|
||||
typename I,
|
||||
bool one_sided = false,
|
||||
std::enable_if_t<std::is_integral_v<I>, int> = 0>
|
||||
struct integer_iterator {
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using value_type = I;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = I*;
|
||||
using reference = I&;
|
||||
|
||||
explicit constexpr integer_iterator(I val) : value(val) {}
|
||||
|
||||
constexpr I operator*() const {
|
||||
return value;
|
||||
}
|
||||
|
||||
constexpr I const* operator->() const {
|
||||
return &value;
|
||||
}
|
||||
|
||||
constexpr integer_iterator& operator++() {
|
||||
++value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr integer_iterator operator++(int) {
|
||||
const auto copy = *this;
|
||||
++*this;
|
||||
return copy;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const integer_iterator& other) const {
|
||||
if constexpr (one_sided) {
|
||||
// Range-for loops' end test is `begin != end`, not `begin <
|
||||
// end`. To handle `c10::irange(n)` where n < 0 (which should be
|
||||
// empty), we just make `begin != end` fail whenever `end` is
|
||||
// negative.
|
||||
return is_negative(other.value) || value == other.value;
|
||||
} else {
|
||||
return value == other.value;
|
||||
}
|
||||
// Suppress "warning: missing return statement at end of non-void function"
|
||||
// which Nvidia's Robert Crovella confirms is an NVCC compiler error
|
||||
// here https://stackoverflow.com/a/64561686/752843 on 2020-10-27
|
||||
// `__builtin_unreachable();` would be best here, but it's not
|
||||
// available with all compilers. So we instead return an arbitrary
|
||||
// value trusting that this line will, in fact, never be reached.
|
||||
return false; // Horrible hack
|
||||
}
|
||||
|
||||
constexpr bool operator!=(const integer_iterator& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
protected:
|
||||
I value;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <
|
||||
typename I,
|
||||
bool one_sided = false,
|
||||
std::enable_if_t<std::is_integral_v<I>, bool> = true>
|
||||
struct integer_range {
|
||||
public:
|
||||
constexpr integer_range(I begin, I end) : begin_(begin), end_(end) {}
|
||||
using iterator = detail::integer_iterator<I, one_sided>;
|
||||
constexpr iterator begin() const {
|
||||
return begin_;
|
||||
}
|
||||
constexpr iterator end() const {
|
||||
return end_;
|
||||
}
|
||||
|
||||
private:
|
||||
iterator begin_;
|
||||
iterator end_;
|
||||
};
|
||||
|
||||
/// Creates an integer range for the half-open interval [begin, end)
|
||||
/// If end<=begin, then the range is empty.
|
||||
/// The range has the type of the `end` integer; `begin` integer is
|
||||
/// cast to this type.
|
||||
template <
|
||||
typename Integer1,
|
||||
typename Integer2,
|
||||
std::enable_if_t<std::is_integral_v<Integer1>, bool> = true,
|
||||
std::enable_if_t<std::is_integral_v<Integer2>, bool> = true>
|
||||
constexpr integer_range<Integer2> irange(Integer1 begin, Integer2 end) {
|
||||
// If end<=begin then the range is empty; we can achieve this effect by
|
||||
// choosing the larger of {begin, end} as the loop terminator
|
||||
return {
|
||||
static_cast<Integer2>(begin),
|
||||
std::max(static_cast<Integer2>(begin), end)};
|
||||
}
|
||||
|
||||
/// Creates an integer range for the half-open interval [0, end)
|
||||
/// If end<=begin, then the range is empty
|
||||
template <
|
||||
typename Integer,
|
||||
std::enable_if_t<std::is_integral_v<Integer>, bool> = true>
|
||||
constexpr integer_range<Integer, true> irange(Integer end) {
|
||||
return {Integer(), end};
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,910 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
//===-- llvm/Support/MathExtras.h - Useful math functions -------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains some functions that are useful for math stuff.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <c10/util/bit_cast.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef __ANDROID_NDK__
|
||||
#include <android/api-level.h>
|
||||
#endif
|
||||
|
||||
#ifndef __has_builtin
|
||||
#define __has_builtin(x) 0
|
||||
#endif
|
||||
|
||||
#ifndef LLVM_GNUC_PREREQ
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
|
||||
#define LLVM_GNUC_PREREQ(maj, min, patch) \
|
||||
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \
|
||||
((maj) << 20) + ((min) << 10) + (patch))
|
||||
#elif defined(__GNUC__) && defined(__GNUC_MINOR__)
|
||||
#define LLVM_GNUC_PREREQ(maj, min, patch) \
|
||||
((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10))
|
||||
#else
|
||||
#define LLVM_GNUC_PREREQ(maj, min, patch) 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Declare these intrinsics manually rather including intrin.h. It's very
|
||||
// expensive, and MathExtras.h is popular.
|
||||
// #include <intrin.h>
|
||||
extern "C" {
|
||||
unsigned char _BitScanForward(unsigned long* _Index, unsigned long _Mask);
|
||||
unsigned char _BitScanForward64(unsigned long* _Index, unsigned __int64 _Mask);
|
||||
unsigned char _BitScanReverse(unsigned long* _Index, unsigned long _Mask);
|
||||
unsigned char _BitScanReverse64(unsigned long* _Index, unsigned __int64 _Mask);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace c10::llvm {
|
||||
/// The behavior an operation has on an input of 0.
|
||||
enum ZeroBehavior {
|
||||
/// The returned value is undefined.
|
||||
ZB_Undefined,
|
||||
/// The returned value is numeric_limits<T>::max()
|
||||
ZB_Max,
|
||||
/// The returned value is numeric_limits<T>::digits
|
||||
ZB_Width
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT>
|
||||
struct TrailingZerosCounter {
|
||||
static std::size_t count(T Val, ZeroBehavior /*unused*/) {
|
||||
if (!Val)
|
||||
return std::numeric_limits<T>::digits;
|
||||
if (Val & 0x1)
|
||||
return 0;
|
||||
|
||||
// Bisection method.
|
||||
std::size_t ZeroBits = 0;
|
||||
T Shift = std::numeric_limits<T>::digits >> 1;
|
||||
T Mask = std::numeric_limits<T>::max() >> Shift;
|
||||
while (Shift) {
|
||||
if ((Val & Mask) == 0) {
|
||||
Val >>= Shift;
|
||||
ZeroBits |= Shift;
|
||||
}
|
||||
Shift >>= 1;
|
||||
Mask >>= Shift;
|
||||
}
|
||||
return ZeroBits;
|
||||
}
|
||||
};
|
||||
|
||||
#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(_MSC_VER)
|
||||
template <typename T>
|
||||
struct TrailingZerosCounter<T, 4> {
|
||||
static std::size_t count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 32;
|
||||
|
||||
#if __has_builtin(__builtin_ctz) || LLVM_GNUC_PREREQ(4, 0, 0)
|
||||
return __builtin_ctz(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanForward(&Index, Val);
|
||||
return Index;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(_MSC_VER) || defined(_M_X64)
|
||||
template <typename T>
|
||||
struct TrailingZerosCounter<T, 8> {
|
||||
static std::size_t count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 64;
|
||||
|
||||
#if __has_builtin(__builtin_ctzll) || LLVM_GNUC_PREREQ(4, 0, 0)
|
||||
return __builtin_ctzll(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanForward64(&Index, Val);
|
||||
return Index;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
/// Count number of 0's from the least significant bit to the most
|
||||
/// stopping at the first 1.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T>
|
||||
std::size_t countTrailingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(
|
||||
std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return llvm::detail::TrailingZerosCounter<T, sizeof(T)>::count(Val, ZB);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT>
|
||||
struct LeadingZerosCounter {
|
||||
static std::size_t count(T Val, ZeroBehavior /*unused*/) {
|
||||
if (!Val)
|
||||
return std::numeric_limits<T>::digits;
|
||||
|
||||
// Bisection method.
|
||||
std::size_t ZeroBits = 0;
|
||||
for (T Shift = std::numeric_limits<T>::digits >> 1; Shift; Shift >>= 1) {
|
||||
T Tmp = Val >> Shift;
|
||||
if (Tmp)
|
||||
Val = Tmp;
|
||||
else
|
||||
ZeroBits |= Shift;
|
||||
}
|
||||
return ZeroBits;
|
||||
}
|
||||
};
|
||||
|
||||
#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(_MSC_VER)
|
||||
template <typename T>
|
||||
struct LeadingZerosCounter<T, 4> {
|
||||
static std::size_t count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 32;
|
||||
|
||||
#if __has_builtin(__builtin_clz) || LLVM_GNUC_PREREQ(4, 0, 0)
|
||||
return __builtin_clz(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanReverse(&Index, Val);
|
||||
return Index ^ 31;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(_MSC_VER) || defined(_M_X64)
|
||||
template <typename T>
|
||||
struct LeadingZerosCounter<T, 8> {
|
||||
static std::size_t count(T Val, ZeroBehavior ZB) {
|
||||
if (ZB != ZB_Undefined && Val == 0)
|
||||
return 64;
|
||||
|
||||
#if __has_builtin(__builtin_clzll) || LLVM_GNUC_PREREQ(4, 0, 0)
|
||||
return __builtin_clzll(Val);
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long Index;
|
||||
_BitScanReverse64(&Index, Val);
|
||||
return Index ^ 63;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
/// Count number of 0's from the most significant bit to the least
|
||||
/// stopping at the first 1.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T>
|
||||
std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(
|
||||
std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return llvm::detail::LeadingZerosCounter<T, sizeof(T)>::count(Val, ZB);
|
||||
}
|
||||
|
||||
/// Get the index of the first set bit starting from the least
|
||||
/// significant bit.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T>
|
||||
T findFirstSet(T Val, ZeroBehavior ZB = ZB_Max) {
|
||||
if (ZB == ZB_Max && Val == 0)
|
||||
return std::numeric_limits<T>::max();
|
||||
|
||||
return countTrailingZeros(Val, ZB_Undefined);
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N right-most bits set to 1, and all other
|
||||
/// bits set to 0. Only unsigned types are allowed.
|
||||
template <typename T>
|
||||
T maskTrailingOnes(unsigned N) {
|
||||
static_assert(std::is_unsigned_v<T>, "Invalid type!");
|
||||
const unsigned Bits = CHAR_BIT * sizeof(T);
|
||||
assert(N <= Bits && "Invalid bit index");
|
||||
return N == 0 ? 0 : (T(-1) >> (Bits - N));
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N left-most bits set to 1, and all other
|
||||
/// bits set to 0. Only unsigned types are allowed.
|
||||
template <typename T>
|
||||
T maskLeadingOnes(unsigned N) {
|
||||
return ~maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N right-most bits set to 0, and all other
|
||||
/// bits set to 1. Only unsigned types are allowed.
|
||||
template <typename T>
|
||||
T maskTrailingZeros(unsigned N) {
|
||||
return maskLeadingOnes<T>(CHAR_BIT * sizeof(T) - N);
|
||||
}
|
||||
|
||||
/// Create a bitmask with the N left-most bits set to 0, and all other
|
||||
/// bits set to 1. Only unsigned types are allowed.
|
||||
template <typename T>
|
||||
T maskLeadingZeros(unsigned N) {
|
||||
return maskTrailingOnes<T>(CHAR_BIT * sizeof(T) - N);
|
||||
}
|
||||
|
||||
/// Get the index of the last set bit starting from the least
|
||||
/// significant bit.
|
||||
///
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of 0. Only ZB_Max and ZB_Undefined are
|
||||
/// valid arguments.
|
||||
template <typename T>
|
||||
T findLastSet(T Val, ZeroBehavior ZB = ZB_Max) {
|
||||
if (ZB == ZB_Max && Val == 0)
|
||||
return std::numeric_limits<T>::max();
|
||||
|
||||
// Use ^ instead of - because both gcc and llvm can remove the associated ^
|
||||
// in the __builtin_clz intrinsic on x86.
|
||||
return countLeadingZeros(Val, ZB_Undefined) ^
|
||||
(std::numeric_limits<T>::digits - 1);
|
||||
}
|
||||
|
||||
/// Macro compressed bit reversal table for 256 bits.
|
||||
///
|
||||
/// http://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
|
||||
/// NOLINTNEXTLINE(*c-arrays*)
|
||||
static constexpr unsigned char BitReverseTable256[256] = {
|
||||
#define R2(n) n, n + 2 * 64, n + 1 * 64, n + 3 * 64
|
||||
#define R4(n) R2(n), R2(n + 2 * 16), R2(n + 1 * 16), R2(n + 3 * 16)
|
||||
#define R6(n) R4(n), R4(n + 2 * 4), R4(n + 1 * 4), R4(n + 3 * 4)
|
||||
R6(0),
|
||||
R6(2),
|
||||
R6(1),
|
||||
R6(3)
|
||||
#undef R2
|
||||
#undef R4
|
||||
#undef R6
|
||||
};
|
||||
|
||||
/// Reverse the bits in \p Val.
|
||||
template <typename T>
|
||||
T reverseBits(T Val) {
|
||||
// NOLINTNEXTLINE(*c-arrays*)
|
||||
unsigned char in[sizeof(Val)];
|
||||
// NOLINTNEXTLINE(*c-arrays*)
|
||||
unsigned char out[sizeof(Val)];
|
||||
std::memcpy(in, &Val, sizeof(Val));
|
||||
for (unsigned i = 0; i < sizeof(Val); ++i)
|
||||
out[(sizeof(Val) - i) - 1] = BitReverseTable256[in[i]];
|
||||
std::memcpy(&Val, out, sizeof(Val));
|
||||
return Val;
|
||||
}
|
||||
|
||||
// NOTE: The following support functions use the _32/_64 extensions instead of
|
||||
// type overloading so that signed and unsigned integers can be used without
|
||||
// ambiguity.
|
||||
|
||||
/// Return the high 32 bits of a 64 bit value.
|
||||
constexpr inline uint32_t Hi_32(uint64_t Value) {
|
||||
return static_cast<uint32_t>(Value >> 32);
|
||||
}
|
||||
|
||||
/// Return the low 32 bits of a 64 bit value.
|
||||
constexpr inline uint32_t Lo_32(uint64_t Value) {
|
||||
return static_cast<uint32_t>(Value);
|
||||
}
|
||||
|
||||
/// Make a 64-bit integer from a high / low pair of 32-bit integers.
|
||||
constexpr inline uint64_t Make_64(uint32_t High, uint32_t Low) {
|
||||
return ((uint64_t)High << 32) | (uint64_t)Low;
|
||||
}
|
||||
|
||||
/// Checks if an integer fits into the given bit width.
|
||||
template <unsigned N>
|
||||
constexpr inline bool isInt(int64_t x) {
|
||||
return N >= 64 ||
|
||||
(-(INT64_C(1) << (N - 1)) <= x && x < (INT64_C(1) << (N - 1)));
|
||||
}
|
||||
// Template specializations to get better code for common cases.
|
||||
template <>
|
||||
constexpr inline bool isInt<8>(int64_t x) {
|
||||
return static_cast<int8_t>(x) == x;
|
||||
}
|
||||
template <>
|
||||
constexpr inline bool isInt<16>(int64_t x) {
|
||||
return static_cast<int16_t>(x) == x;
|
||||
}
|
||||
template <>
|
||||
constexpr inline bool isInt<32>(int64_t x) {
|
||||
return static_cast<int32_t>(x) == x;
|
||||
}
|
||||
|
||||
/// Checks if a signed integer is an N bit number shifted left by S.
|
||||
template <unsigned N, unsigned S>
|
||||
constexpr inline bool isShiftedInt(int64_t x) {
|
||||
static_assert(
|
||||
N > 0, "isShiftedInt<0> doesn't make sense (refers to a 0-bit number.");
|
||||
static_assert(N + S <= 64, "isShiftedInt<N, S> with N + S > 64 is too wide.");
|
||||
return isInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
|
||||
}
|
||||
|
||||
/// Checks if an unsigned integer fits into the given bit width.
|
||||
///
|
||||
/// This is written as two functions rather than as simply
|
||||
///
|
||||
/// return N >= 64 || X < (UINT64_C(1) << N);
|
||||
///
|
||||
/// to keep MSVC from (incorrectly) warning on isUInt<64> that we're shifting
|
||||
/// left too many places.
|
||||
template <unsigned N>
|
||||
constexpr inline std::enable_if_t<(N < 64), bool> isUInt(uint64_t X) {
|
||||
static_assert(N > 0, "isUInt<0> doesn't make sense");
|
||||
return X < (UINT64_C(1) << N);
|
||||
}
|
||||
template <unsigned N>
|
||||
constexpr inline std::enable_if_t<N >= 64, bool> isUInt(uint64_t /*X*/) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Template specializations to get better code for common cases.
|
||||
template <>
|
||||
constexpr inline bool isUInt<8>(uint64_t x) {
|
||||
return static_cast<uint8_t>(x) == x;
|
||||
}
|
||||
template <>
|
||||
constexpr inline bool isUInt<16>(uint64_t x) {
|
||||
return static_cast<uint16_t>(x) == x;
|
||||
}
|
||||
template <>
|
||||
constexpr inline bool isUInt<32>(uint64_t x) {
|
||||
return static_cast<uint32_t>(x) == x;
|
||||
}
|
||||
|
||||
/// Checks if a unsigned integer is an N bit number shifted left by S.
|
||||
template <unsigned N, unsigned S>
|
||||
constexpr inline bool isShiftedUInt(uint64_t x) {
|
||||
static_assert(
|
||||
N > 0, "isShiftedUInt<0> doesn't make sense (refers to a 0-bit number)");
|
||||
static_assert(
|
||||
N + S <= 64, "isShiftedUInt<N, S> with N + S > 64 is too wide.");
|
||||
// Per the two static_asserts above, S must be strictly less than 64. So
|
||||
// 1 << S is not undefined behavior.
|
||||
return isUInt<N + S>(x) && (x % (UINT64_C(1) << S) == 0);
|
||||
}
|
||||
|
||||
/// Gets the maximum value for a N-bit unsigned integer.
|
||||
inline uint64_t maxUIntN(uint64_t N) {
|
||||
assert(N > 0 && N <= 64 && "integer width out of range");
|
||||
|
||||
// uint64_t(1) << 64 is undefined behavior, so we can't do
|
||||
// (uint64_t(1) << N) - 1
|
||||
// without checking first that N != 64. But this works and doesn't have a
|
||||
// branch.
|
||||
return UINT64_MAX >> (64 - N);
|
||||
}
|
||||
|
||||
// Ignore the false warning "Arithmetic overflow" for MSVC
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4146)
|
||||
#endif
|
||||
|
||||
/// Gets the minimum value for a N-bit signed integer.
|
||||
inline int64_t minIntN(int64_t N) {
|
||||
assert(N > 0 && N <= 64 && "integer width out of range");
|
||||
// NOLINTNEXTLINE(*-narrowing-conversions)
|
||||
return -(UINT64_C(1) << (N - 1));
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
/// Gets the maximum value for a N-bit signed integer.
|
||||
inline int64_t maxIntN(int64_t N) {
|
||||
assert(N > 0 && N <= 64 && "integer width out of range");
|
||||
|
||||
// This relies on two's complement wraparound when N == 64, so we convert to
|
||||
// int64_t only at the very end to avoid UB.
|
||||
// NOLINTNEXTLINE(*-narrowing-conversions)
|
||||
return (UINT64_C(1) << (N - 1)) - 1;
|
||||
}
|
||||
|
||||
/// Checks if an unsigned integer fits into the given (dynamic) bit width.
|
||||
inline bool isUIntN(unsigned N, uint64_t x) {
|
||||
return N >= 64 || x <= maxUIntN(N);
|
||||
}
|
||||
|
||||
/// Checks if an signed integer fits into the given (dynamic) bit width.
|
||||
inline bool isIntN(unsigned N, int64_t x) {
|
||||
return N >= 64 || (minIntN(N) <= x && x <= maxIntN(N));
|
||||
}
|
||||
|
||||
/// Return true if the argument is a non-empty sequence of ones starting at the
|
||||
/// least significant bit with the remainder zero (32 bit version).
|
||||
/// Ex. isMask_32(0x0000FFFFU) == true.
|
||||
constexpr inline bool isMask_32(uint32_t Value) {
|
||||
return Value && ((Value + 1) & Value) == 0;
|
||||
}
|
||||
|
||||
/// Return true if the argument is a non-empty sequence of ones starting at the
|
||||
/// least significant bit with the remainder zero (64 bit version).
|
||||
constexpr inline bool isMask_64(uint64_t Value) {
|
||||
return Value && ((Value + 1) & Value) == 0;
|
||||
}
|
||||
|
||||
/// Return true if the argument contains a non-empty sequence of ones with the
|
||||
/// remainder zero (32 bit version.) Ex. isShiftedMask_32(0x0000FF00U) == true.
|
||||
constexpr inline bool isShiftedMask_32(uint32_t Value) {
|
||||
return Value && isMask_32((Value - 1) | Value);
|
||||
}
|
||||
|
||||
/// Return true if the argument contains a non-empty sequence of ones with the
|
||||
/// remainder zero (64 bit version.)
|
||||
constexpr inline bool isShiftedMask_64(uint64_t Value) {
|
||||
return Value && isMask_64((Value - 1) | Value);
|
||||
}
|
||||
|
||||
/// Return true if the argument is a power of two > 0.
|
||||
/// Ex. isPowerOf2_32(0x00100000U) == true (32 bit edition.)
|
||||
constexpr inline bool isPowerOf2_32(uint32_t Value) {
|
||||
return Value && !(Value & (Value - 1));
|
||||
}
|
||||
|
||||
/// Return true if the argument is a power of two > 0 (64 bit edition.)
|
||||
constexpr inline bool isPowerOf2_64(uint64_t Value) {
|
||||
return Value && !(Value & (Value - 1));
|
||||
}
|
||||
|
||||
/// Count the number of ones from the most significant bit to the first
|
||||
/// zero bit.
|
||||
///
|
||||
/// Ex. countLeadingOnes(0xFF0FFF00) == 8.
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
|
||||
/// ZB_Undefined are valid arguments.
|
||||
template <typename T>
|
||||
std::size_t countLeadingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(
|
||||
std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return countLeadingZeros<T>(~Value, ZB);
|
||||
}
|
||||
|
||||
/// Count the number of ones from the least significant bit to the first
|
||||
/// zero bit.
|
||||
///
|
||||
/// Ex. countTrailingOnes(0x00FF00FF) == 8.
|
||||
/// Only unsigned integral types are allowed.
|
||||
///
|
||||
/// \param ZB the behavior on an input of all ones. Only ZB_Width and
|
||||
/// ZB_Undefined are valid arguments.
|
||||
template <typename T>
|
||||
std::size_t countTrailingOnes(T Value, ZeroBehavior ZB = ZB_Width) {
|
||||
static_assert(
|
||||
std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return countTrailingZeros<T>(~Value, ZB);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T, std::size_t SizeOfT>
|
||||
struct PopulationCounter {
|
||||
static unsigned count(T Value) {
|
||||
// Generic version, forward to 32 bits.
|
||||
static_assert(SizeOfT <= 4, "Not implemented!");
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
return __builtin_popcount(Value);
|
||||
#else
|
||||
uint32_t v = Value;
|
||||
v = v - ((v >> 1) & 0x55555555);
|
||||
v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
|
||||
return ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PopulationCounter<T, 8> {
|
||||
static unsigned count(T Value) {
|
||||
#if defined(__GNUC__) && __GNUC__ >= 4
|
||||
return __builtin_popcountll(Value);
|
||||
#else
|
||||
uint64_t v = Value;
|
||||
v = v - ((v >> 1) & 0x5555555555555555ULL);
|
||||
v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL);
|
||||
v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0FULL;
|
||||
return unsigned((uint64_t)(v * 0x0101010101010101ULL) >> 56);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
/// Count the number of set bits in a value.
|
||||
/// Ex. countPopulation(0xF000F000) = 8
|
||||
/// Returns 0 if the word is zero.
|
||||
template <typename T>
|
||||
inline unsigned countPopulation(T Value) {
|
||||
static_assert(
|
||||
std::numeric_limits<T>::is_integer && !std::numeric_limits<T>::is_signed,
|
||||
"Only unsigned integral types are allowed.");
|
||||
return detail::PopulationCounter<T, sizeof(T)>::count(Value);
|
||||
}
|
||||
|
||||
/// Return the log base 2 of the specified value.
|
||||
inline double Log2(double Value) {
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ < 18
|
||||
return __builtin_log(Value) / __builtin_log(2.0);
|
||||
#else
|
||||
return log2(Value);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Return the floor log base 2 of the specified value, -1 if the value is zero.
|
||||
/// (32 bit edition.)
|
||||
/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2
|
||||
inline unsigned Log2_32(uint32_t Value) {
|
||||
return static_cast<unsigned>(31 - countLeadingZeros(Value));
|
||||
}
|
||||
|
||||
/// Return the floor log base 2 of the specified value, -1 if the value is zero.
|
||||
/// (64 bit edition.)
|
||||
inline unsigned Log2_64(uint64_t Value) {
|
||||
return static_cast<unsigned>(63 - countLeadingZeros(Value));
|
||||
}
|
||||
|
||||
/// Return the ceil log base 2 of the specified value, 32 if the value is zero.
|
||||
/// (32 bit edition).
|
||||
/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3
|
||||
inline unsigned Log2_32_Ceil(uint32_t Value) {
|
||||
return static_cast<unsigned>(32 - countLeadingZeros(Value - 1));
|
||||
}
|
||||
|
||||
/// Return the ceil log base 2 of the specified value, 64 if the value is zero.
|
||||
/// (64 bit edition.)
|
||||
inline unsigned Log2_64_Ceil(uint64_t Value) {
|
||||
return static_cast<unsigned>(64 - countLeadingZeros(Value - 1));
|
||||
}
|
||||
|
||||
/// Return the greatest common divisor of the values using Euclid's algorithm.
|
||||
inline uint64_t GreatestCommonDivisor64(uint64_t A, uint64_t B) {
|
||||
while (B) {
|
||||
uint64_t T = B;
|
||||
B = A % B;
|
||||
A = T;
|
||||
}
|
||||
return A;
|
||||
}
|
||||
|
||||
/// This function takes a 64-bit integer and returns the bit equivalent double.
|
||||
inline double BitsToDouble(uint64_t Bits) {
|
||||
double D = 0;
|
||||
static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
|
||||
memcpy(&D, &Bits, sizeof(Bits));
|
||||
return D;
|
||||
}
|
||||
|
||||
/// This function takes a 32-bit integer and returns the bit equivalent float.
|
||||
inline float BitsToFloat(uint32_t Bits) {
|
||||
// TODO: Use std::bit_cast once C++20 becomes available.
|
||||
return c10::bit_cast<float>(Bits);
|
||||
}
|
||||
|
||||
/// This function takes a double and returns the bit equivalent 64-bit integer.
|
||||
/// Note that copying doubles around changes the bits of NaNs on some hosts,
|
||||
/// notably x86, so this routine cannot be used if these bits are needed.
|
||||
inline uint64_t DoubleToBits(double Double) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
||||
uint64_t Bits;
|
||||
static_assert(sizeof(uint64_t) == sizeof(double), "Unexpected type sizes");
|
||||
memcpy(&Bits, &Double, sizeof(Double));
|
||||
return Bits;
|
||||
}
|
||||
|
||||
/// This function takes a float and returns the bit equivalent 32-bit integer.
|
||||
/// Note that copying floats around changes the bits of NaNs on some hosts,
|
||||
/// notably x86, so this routine cannot be used if these bits are needed.
|
||||
inline uint32_t FloatToBits(float Float) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
||||
uint32_t Bits;
|
||||
static_assert(sizeof(uint32_t) == sizeof(float), "Unexpected type sizes");
|
||||
memcpy(&Bits, &Float, sizeof(Float));
|
||||
return Bits;
|
||||
}
|
||||
|
||||
/// A and B are either alignments or offsets. Return the minimum alignment that
|
||||
/// may be assumed after adding the two together.
|
||||
constexpr inline uint64_t MinAlign(uint64_t A, uint64_t B) {
|
||||
// The largest power of 2 that divides both A and B.
|
||||
//
|
||||
// Replace "-Value" by "1+~Value" in the following commented code to avoid
|
||||
// MSVC warning C4146
|
||||
// return (A | B) & -(A | B);
|
||||
return (A | B) & (1 + ~(A | B));
|
||||
}
|
||||
|
||||
/// Aligns \c Addr to \c Alignment bytes, rounding up.
|
||||
///
|
||||
/// Alignment should be a power of two. This method rounds up, so
|
||||
/// alignAddr(7, 4) == 8 and alignAddr(8, 4) == 8.
|
||||
inline uintptr_t alignAddr(const void* Addr, size_t Alignment) {
|
||||
assert(
|
||||
Alignment && isPowerOf2_64((uint64_t)Alignment) &&
|
||||
"Alignment is not a power of two!");
|
||||
|
||||
assert((uintptr_t)Addr + Alignment - 1 >= (uintptr_t)Addr);
|
||||
|
||||
return (((uintptr_t)Addr + Alignment - 1) & ~(uintptr_t)(Alignment - 1));
|
||||
}
|
||||
|
||||
/// Returns the necessary adjustment for aligning \c Ptr to \c Alignment
|
||||
/// bytes, rounding up.
|
||||
inline size_t alignmentAdjustment(const void* Ptr, size_t Alignment) {
|
||||
return alignAddr(Ptr, Alignment) - (uintptr_t)Ptr;
|
||||
}
|
||||
|
||||
/// Returns the next power of two (in 64-bits) that is strictly greater than A.
|
||||
/// Returns zero on overflow.
|
||||
inline uint64_t NextPowerOf2(uint64_t A) {
|
||||
A |= (A >> 1);
|
||||
A |= (A >> 2);
|
||||
A |= (A >> 4);
|
||||
A |= (A >> 8);
|
||||
A |= (A >> 16);
|
||||
A |= (A >> 32);
|
||||
return A + 1;
|
||||
}
|
||||
|
||||
/// Returns the power of two which is less than or equal to the given value.
|
||||
/// Essentially, it is a floor operation across the domain of powers of two.
|
||||
inline uint64_t PowerOf2Floor(uint64_t A) {
|
||||
if (!A)
|
||||
return 0;
|
||||
return 1ull << (63 - countLeadingZeros(A, ZB_Undefined));
|
||||
}
|
||||
|
||||
/// Returns the power of two which is greater than or equal to the given value.
|
||||
/// Essentially, it is a ceil operation across the domain of powers of two.
|
||||
inline uint64_t PowerOf2Ceil(uint64_t A) {
|
||||
if (!A)
|
||||
return 0;
|
||||
return NextPowerOf2(A - 1);
|
||||
}
|
||||
|
||||
/// Returns the next integer (mod 2**64) that is greater than or equal to
|
||||
/// \p Value and is a multiple of \p Align. \p Align must be non-zero.
|
||||
///
|
||||
/// If non-zero \p Skew is specified, the return value will be a minimal
|
||||
/// integer that is greater than or equal to \p Value and equal to
|
||||
/// \p Align * N + \p Skew for some integer N. If \p Skew is larger than
|
||||
/// \p Align, its value is adjusted to '\p Skew mod \p Align'.
|
||||
///
|
||||
/// Examples:
|
||||
/// \code
|
||||
/// alignTo(5, 8) = 8
|
||||
/// alignTo(17, 8) = 24
|
||||
/// alignTo(~0LL, 8) = 0
|
||||
/// alignTo(321, 255) = 510
|
||||
///
|
||||
/// alignTo(5, 8, 7) = 7
|
||||
/// alignTo(17, 8, 1) = 17
|
||||
/// alignTo(~0LL, 8, 3) = 3
|
||||
/// alignTo(321, 255, 42) = 552
|
||||
/// \endcode
|
||||
inline uint64_t alignTo(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
|
||||
assert(Align != 0u && "Align can't be 0.");
|
||||
Skew %= Align;
|
||||
return (Value + Align - 1 - Skew) / Align * Align + Skew;
|
||||
}
|
||||
|
||||
/// Returns the next integer (mod 2**64) that is greater than or equal to
|
||||
/// \p Value and is a multiple of \c Align. \c Align must be non-zero.
|
||||
template <uint64_t Align>
|
||||
constexpr inline uint64_t alignTo(uint64_t Value) {
|
||||
static_assert(Align != 0u, "Align must be non-zero");
|
||||
return (Value + Align - 1) / Align * Align;
|
||||
}
|
||||
|
||||
/// Returns the integer ceil(Numerator / Denominator).
|
||||
inline uint64_t divideCeil(uint64_t Numerator, uint64_t Denominator) {
|
||||
return alignTo(Numerator, Denominator) / Denominator;
|
||||
}
|
||||
|
||||
/// \c alignTo for contexts where a constant expression is required.
|
||||
/// \sa alignTo
|
||||
///
|
||||
/// \todo FIXME: remove when \c constexpr becomes really \c constexpr
|
||||
template <uint64_t Align>
|
||||
struct AlignTo {
|
||||
static_assert(Align != 0u, "Align must be non-zero");
|
||||
template <uint64_t Value>
|
||||
struct from_value {
|
||||
static const uint64_t value = (Value + Align - 1) / Align * Align;
|
||||
};
|
||||
};
|
||||
|
||||
/// Returns the largest uint64_t less than or equal to \p Value and is
|
||||
/// \p Skew mod \p Align. \p Align must be non-zero
|
||||
inline uint64_t alignDown(uint64_t Value, uint64_t Align, uint64_t Skew = 0) {
|
||||
assert(Align != 0u && "Align can't be 0.");
|
||||
Skew %= Align;
|
||||
return (Value - Skew) / Align * Align + Skew;
|
||||
}
|
||||
|
||||
/// Returns the offset to the next integer (mod 2**64) that is greater than
|
||||
/// or equal to \p Value and is a multiple of \p Align. \p Align must be
|
||||
/// non-zero.
|
||||
inline uint64_t OffsetToAlignment(uint64_t Value, uint64_t Align) {
|
||||
return alignTo(Value, Align) - Value;
|
||||
}
|
||||
|
||||
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
|
||||
/// Requires 0 < B <= 32.
|
||||
template <unsigned B>
|
||||
constexpr inline int32_t SignExtend32(uint32_t X) {
|
||||
static_assert(B > 0, "Bit width can't be 0.");
|
||||
static_assert(B <= 32, "Bit width out of range.");
|
||||
return int32_t(X << (32 - B)) >> (32 - B);
|
||||
}
|
||||
|
||||
/// Sign-extend the number in the bottom B bits of X to a 32-bit integer.
|
||||
/// Requires 0 < B < 32.
|
||||
inline int32_t SignExtend32(uint32_t X, unsigned B) {
|
||||
assert(B > 0 && "Bit width can't be 0.");
|
||||
assert(B <= 32 && "Bit width out of range.");
|
||||
return int32_t(X << (32 - B)) >> (32 - B);
|
||||
}
|
||||
|
||||
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
|
||||
/// Requires 0 < B < 64.
|
||||
template <unsigned B>
|
||||
constexpr inline int64_t SignExtend64(uint64_t x) {
|
||||
static_assert(B > 0, "Bit width can't be 0.");
|
||||
static_assert(B <= 64, "Bit width out of range.");
|
||||
return int64_t(x << (64 - B)) >> (64 - B);
|
||||
}
|
||||
|
||||
/// Sign-extend the number in the bottom B bits of X to a 64-bit integer.
|
||||
/// Requires 0 < B < 64.
|
||||
inline int64_t SignExtend64(uint64_t X, unsigned B) {
|
||||
assert(B > 0 && "Bit width can't be 0.");
|
||||
assert(B <= 64 && "Bit width out of range.");
|
||||
return int64_t(X << (64 - B)) >> (64 - B);
|
||||
}
|
||||
|
||||
/// Subtract two unsigned integers, X and Y, of type T and return the absolute
|
||||
/// value of the result.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_unsigned_v<T>, T> AbsoluteDifference(T X, T Y) {
|
||||
return std::max(X, Y) - std::min(X, Y);
|
||||
}
|
||||
|
||||
/// Add two unsigned integers, X and Y, of type T. Clamp the result to the
|
||||
/// maximum representable value of T on overflow. ResultOverflowed indicates if
|
||||
/// the result is larger than the maximum representable value of type T.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_unsigned_v<T>, T> SaturatingAdd(
|
||||
T X,
|
||||
T Y,
|
||||
bool* ResultOverflowed = nullptr) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
||||
bool Dummy;
|
||||
bool& Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
|
||||
// Hacker's Delight, p. 29
|
||||
T Z = X + Y;
|
||||
Overflowed = (Z < X || Z < Y);
|
||||
if (Overflowed)
|
||||
return std::numeric_limits<T>::max();
|
||||
else
|
||||
return Z;
|
||||
}
|
||||
|
||||
/// Multiply two unsigned integers, X and Y, of type T. Clamp the result to the
|
||||
/// maximum representable value of T on overflow. ResultOverflowed indicates if
|
||||
/// the result is larger than the maximum representable value of type T.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_unsigned_v<T>, T> SaturatingMultiply(
|
||||
T X,
|
||||
T Y,
|
||||
bool* ResultOverflowed = nullptr) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
||||
bool Dummy;
|
||||
bool& Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
|
||||
|
||||
// Hacker's Delight, p. 30 has a different algorithm, but we don't use that
|
||||
// because it fails for uint16_t (where multiplication can have undefined
|
||||
// behavior due to promotion to int), and requires a division in addition
|
||||
// to the multiplication.
|
||||
|
||||
Overflowed = false;
|
||||
|
||||
// Log2(Z) would be either Log2Z or Log2Z + 1.
|
||||
// Special case: if X or Y is 0, Log2_64 gives -1, and Log2Z
|
||||
// will necessarily be less than Log2Max as desired.
|
||||
int Log2Z = Log2_64(X) + Log2_64(Y);
|
||||
const T Max = std::numeric_limits<T>::max();
|
||||
int Log2Max = Log2_64(Max);
|
||||
if (Log2Z < Log2Max) {
|
||||
return X * Y;
|
||||
}
|
||||
if (Log2Z > Log2Max) {
|
||||
Overflowed = true;
|
||||
return Max;
|
||||
}
|
||||
|
||||
// We're going to use the top bit, and maybe overflow one
|
||||
// bit past it. Multiply all but the bottom bit then add
|
||||
// that on at the end.
|
||||
T Z = (X >> 1) * Y;
|
||||
if (Z & ~(Max >> 1)) {
|
||||
Overflowed = true;
|
||||
return Max;
|
||||
}
|
||||
Z <<= 1;
|
||||
if (X & 1)
|
||||
return SaturatingAdd(Z, Y, ResultOverflowed);
|
||||
|
||||
return Z;
|
||||
}
|
||||
|
||||
/// Multiply two unsigned integers, X and Y, and add the unsigned integer, A to
|
||||
/// the product. Clamp the result to the maximum representable value of T on
|
||||
/// overflow. ResultOverflowed indicates if the result is larger than the
|
||||
/// maximum representable value of type T.
|
||||
template <typename T>
|
||||
std::enable_if_t<std::is_unsigned_v<T>, T> SaturatingMultiplyAdd(
|
||||
T X,
|
||||
T Y,
|
||||
T A,
|
||||
bool* ResultOverflowed = nullptr) {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-init-variables)
|
||||
bool Dummy;
|
||||
bool& Overflowed = ResultOverflowed ? *ResultOverflowed : Dummy;
|
||||
|
||||
T Product = SaturatingMultiply(X, Y, &Overflowed);
|
||||
if (Overflowed)
|
||||
return Product;
|
||||
|
||||
return SaturatingAdd(A, Product, &Overflowed);
|
||||
}
|
||||
|
||||
/// Use this rather than HUGE_VALF; the latter causes warnings on MSVC.
|
||||
extern const float huge_valf;
|
||||
} // namespace c10::llvm
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,80 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#ifndef C10_UTIL_LOGGING_COMMON_H_
|
||||
#define C10_UTIL_LOGGING_COMMON_H_
|
||||
|
||||
#include <c10/macros/Export.h>
|
||||
#include <c10/util/StringUtil.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// MessageLogger that throws exceptions instead of aborting (glog version)
|
||||
// or logs and may abort (non-glog version).
|
||||
class C10_API MessageLogger {
|
||||
public:
|
||||
MessageLogger(
|
||||
SourceLocation source_location,
|
||||
int severity,
|
||||
bool exit_on_fatal = true);
|
||||
~MessageLogger() noexcept(false);
|
||||
|
||||
// Return the stream associated with the logger object.
|
||||
std::stringstream& stream();
|
||||
|
||||
private:
|
||||
// When there is a fatal log, and fatal == true, we abort
|
||||
// otherwise, we throw.
|
||||
void DealWithFatal();
|
||||
|
||||
#if defined(ANDROID) && !defined(C10_USE_GLOG)
|
||||
const char* tag_{"native"};
|
||||
#endif
|
||||
std::stringstream stream_;
|
||||
int severity_;
|
||||
bool exit_on_fatal_;
|
||||
SourceLocation source_location_;
|
||||
};
|
||||
|
||||
// This class is used to explicitly ignore values in the conditional
|
||||
// logging macros. This avoids compiler warnings like "value computed
|
||||
// is not used" and "statement has no effect".
|
||||
class C10_API LoggerVoidify {
|
||||
public:
|
||||
LoggerVoidify() = default;
|
||||
// This has to be an operator with a precedence lower than << but
|
||||
// higher than ?:
|
||||
void operator&(const std::ostream& s [[maybe_unused]]) {}
|
||||
};
|
||||
|
||||
// Forward declarations for CheckNotNull functions
|
||||
template <typename T>
|
||||
T& CheckNotNullCommon(
|
||||
const char* file,
|
||||
int line,
|
||||
const char* names,
|
||||
T& t,
|
||||
bool fatal = true);
|
||||
|
||||
template <typename T>
|
||||
T* CheckNotNull(
|
||||
const char* file,
|
||||
int line,
|
||||
const char* names,
|
||||
T* t,
|
||||
bool fatal = true);
|
||||
|
||||
template <typename T>
|
||||
T& CheckNotNull(
|
||||
const char* file,
|
||||
int line,
|
||||
const char* names,
|
||||
T& t,
|
||||
bool fatal = true);
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#endif // C10_UTIL_LOGGING_COMMON_H_
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#ifndef C10_UTIL_LOGGING_IS_GOOGLE_GLOG_H_
|
||||
#define C10_UTIL_LOGGING_IS_GOOGLE_GLOG_H_
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <iomanip> // because some of the caffe2 code uses e.g. std::setw
|
||||
// Using google glog. For glog 0.3.2 versions, stl_logging.h needs to be before
|
||||
// logging.h to actually use stl_logging. Because template magic.
|
||||
// In addition, we do not do stl logging in .cu files because nvcc does not like
|
||||
// it. Some mobile platforms do not like stl_logging, so we add an
|
||||
// overload in that case as well.
|
||||
|
||||
#ifdef __CUDACC__
|
||||
#include <cuda.h>
|
||||
#endif
|
||||
|
||||
#if !defined(__CUDACC__) && !defined(C10_USE_MINIMAL_GLOG)
|
||||
#include <glog/stl_logging.h>
|
||||
|
||||
// Old versions of glog don't declare this using declaration, so help
|
||||
// them out. Fortunately, C++ won't complain if you declare the same
|
||||
// using declaration multiple times.
|
||||
namespace std {
|
||||
using ::operator<<;
|
||||
}
|
||||
|
||||
#else // !defined(__CUDACC__) && !defined(C10_USE_MINIMAL_GLOG)
|
||||
|
||||
// In the cudacc compiler scenario, we will simply ignore the container
|
||||
// printout feature. Basically we need to register a fake overload for
|
||||
// vector/string - here, we just ignore the entries in the logs.
|
||||
|
||||
namespace std {
|
||||
#define INSTANTIATE_FOR_CONTAINER(container) \
|
||||
template <class... Types> \
|
||||
ostream& operator<<(ostream& out, const container<Types...>&) { \
|
||||
return out; \
|
||||
}
|
||||
|
||||
INSTANTIATE_FOR_CONTAINER(vector)
|
||||
INSTANTIATE_FOR_CONTAINER(map)
|
||||
INSTANTIATE_FOR_CONTAINER(set)
|
||||
#undef INSTANTIATE_FOR_CONTAINER
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
|
||||
#include <c10/util/logging_common.h>
|
||||
#include <glog/logging.h>
|
||||
|
||||
namespace c10 {
|
||||
|
||||
[[noreturn]] void ThrowEnforceNotMet(
|
||||
const char* file,
|
||||
const int line,
|
||||
const char* condition,
|
||||
const std::string& msg,
|
||||
const void* caller);
|
||||
|
||||
template <typename T>
|
||||
T& CheckNotNullCommon(
|
||||
const char* file,
|
||||
int line,
|
||||
const char* names,
|
||||
T& t,
|
||||
bool fatal) {
|
||||
if (t == nullptr) {
|
||||
MessageLogger(
|
||||
SourceLocation::current(file, nullptr, line),
|
||||
::google::GLOG_FATAL,
|
||||
fatal)
|
||||
.stream()
|
||||
<< "Check failed: '" << names << "' must be non NULL. ";
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* CheckNotNull(
|
||||
const char* file,
|
||||
int line,
|
||||
const char* names,
|
||||
T* t,
|
||||
bool fatal) {
|
||||
return CheckNotNullCommon(file, line, names, t, fatal);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& CheckNotNull(
|
||||
const char* file,
|
||||
int line,
|
||||
const char* names,
|
||||
T& t,
|
||||
bool fatal) {
|
||||
return CheckNotNullCommon(file, line, names, t, fatal);
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
// Log with source location information override (to be used in generic
|
||||
// warning/error handlers implemented as functions, not macros)
|
||||
//
|
||||
// Note, we don't respect GOOGLE_STRIP_LOG here for simplicity
|
||||
#define LOG_AT_FILE_LINE(n, file, line) \
|
||||
::google::LogMessage(file, line, ::google::GLOG_##n).stream()
|
||||
|
||||
#endif // C10_UTIL_LOGGING_IS_GOOGLE_GLOG_H_
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#ifndef C10_UTIL_LOGGING_IS_NOT_GOOGLE_GLOG_H_
|
||||
#define C10_UTIL_LOGGING_IS_NOT_GOOGLE_GLOG_H_
|
||||
|
||||
#include <chrono>
|
||||
#include <climits>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <c10/util/Flags.h>
|
||||
#include <c10/util/logging_common.h>
|
||||
|
||||
const char CAFFE2_SEVERITY_PREFIX[] = "FEWIV";
|
||||
|
||||
namespace c10 {
|
||||
|
||||
// Log severity level constants.
|
||||
const int GLOG_FATAL = 3;
|
||||
const int GLOG_ERROR = 2;
|
||||
const int GLOG_WARNING = 1;
|
||||
const int GLOG_INFO = 0;
|
||||
|
||||
// Helpers for TORCH_CHECK_NOTNULL(). Two are necessary to support both raw
|
||||
// pointers and smart pointers.
|
||||
template <typename T>
|
||||
T& CheckNotNullCommon(
|
||||
const char* file,
|
||||
int line,
|
||||
const char* names,
|
||||
T& t,
|
||||
bool fatal) {
|
||||
if (t == nullptr) {
|
||||
MessageLogger(
|
||||
SourceLocation::current(file, nullptr, line), GLOG_FATAL, fatal)
|
||||
.stream()
|
||||
<< "Check failed: '" << names << "' must be non NULL. ";
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* CheckNotNull(
|
||||
const char* file,
|
||||
int line,
|
||||
const char* names,
|
||||
T* t,
|
||||
bool fatal) {
|
||||
return CheckNotNullCommon(file, line, names, t, fatal);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T& CheckNotNull(
|
||||
const char* file,
|
||||
int line,
|
||||
const char* names,
|
||||
T& t,
|
||||
bool fatal) {
|
||||
return CheckNotNullCommon(file, line, names, t, fatal);
|
||||
}
|
||||
} // namespace c10
|
||||
|
||||
// ---------------------- Logging Macro definitions --------------------------
|
||||
|
||||
static_assert(
|
||||
CAFFE2_LOG_THRESHOLD <= ::c10::GLOG_FATAL,
|
||||
"CAFFE2_LOG_THRESHOLD should at most be GLOG_FATAL.");
|
||||
// If n is under the compile time caffe log threshold, The _CAFFE_LOG(n)
|
||||
// should not generate anything in optimized code.
|
||||
#define LOG(n) \
|
||||
if (::c10::GLOG_##n >= CAFFE2_LOG_THRESHOLD) \
|
||||
::c10::MessageLogger(::c10::SourceLocation::current(), ::c10::GLOG_##n) \
|
||||
.stream()
|
||||
#define VLOG(n) \
|
||||
if (-n >= CAFFE2_LOG_THRESHOLD) \
|
||||
::c10::MessageLogger(::c10::SourceLocation::current(), -n).stream()
|
||||
|
||||
#define LOG_IF(n, condition) \
|
||||
if (::c10::GLOG_##n >= CAFFE2_LOG_THRESHOLD && (condition)) \
|
||||
::c10::MessageLogger(::c10::SourceLocation::current(), ::c10::GLOG_##n) \
|
||||
.stream()
|
||||
#define VLOG_IF(n, condition) \
|
||||
if (-n >= CAFFE2_LOG_THRESHOLD && (condition)) \
|
||||
::c10::MessageLogger(::c10::SourceLocation::current(), -n).stream()
|
||||
|
||||
#define VLOG_IS_ON(verboselevel) (CAFFE2_LOG_THRESHOLD <= -(verboselevel))
|
||||
|
||||
// Log with source location information override (to be used in generic
|
||||
// warning/error handlers implemented as functions, not macros)
|
||||
#define LOG_AT_FILE_LINE(n, file, line) \
|
||||
if (::c10::GLOG_##n >= CAFFE2_LOG_THRESHOLD) \
|
||||
::c10::MessageLogger( \
|
||||
::c10::SourceLocation::current(file, nullptr, line), ::c10::GLOG_##n) \
|
||||
.stream()
|
||||
// Log only if condition is met. Otherwise evaluates to void.
|
||||
#define FATAL_IF(condition) \
|
||||
condition ? (void)0 \
|
||||
: ::c10::LoggerVoidify() & \
|
||||
::c10::MessageLogger( \
|
||||
::c10::SourceLocation::current(), ::c10::GLOG_FATAL) \
|
||||
.stream()
|
||||
|
||||
// Check for a given boolean condition.
|
||||
#define CHECK(condition) FATAL_IF(condition) << "Check failed: " #condition " "
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Debug only version of CHECK
|
||||
#define DCHECK(condition) FATAL_IF(condition) << "Check failed: " #condition " "
|
||||
#define DLOG(severity) LOG(severity)
|
||||
#else // NDEBUG
|
||||
// Optimized version - generates no code.
|
||||
#define DCHECK(condition) \
|
||||
while (false) \
|
||||
CHECK(condition)
|
||||
|
||||
#define DLOG(n) \
|
||||
true ? (void)0 \
|
||||
: ::c10::LoggerVoidify() & \
|
||||
::c10::MessageLogger( \
|
||||
::c10::SourceLocation::current(), ::c10::GLOG_##n) \
|
||||
.stream()
|
||||
#endif // NDEBUG
|
||||
|
||||
// ---------------------- Support for std objects --------------------------
|
||||
// These are adapted from glog to support a limited set of logging capability
|
||||
// for STL objects.
|
||||
|
||||
namespace std {
|
||||
// Forward declare these two, and define them after all the container streams
|
||||
// operators so that we can recurse from pair -> container -> container -> pair
|
||||
// properly.
|
||||
template <class First, class Second>
|
||||
std::ostream& operator<<(std::ostream& out, const std::pair<First, Second>& p);
|
||||
} // namespace std
|
||||
|
||||
namespace c10 {
|
||||
template <class Iter>
|
||||
void PrintSequence(std::ostream& ss, Iter begin, Iter end);
|
||||
} // namespace c10
|
||||
|
||||
namespace std {
|
||||
#define INSTANTIATE_FOR_CONTAINER(container) \
|
||||
template <class... Types> \
|
||||
std::ostream& operator<<( \
|
||||
std::ostream& out, const container<Types...>& seq) { \
|
||||
c10::PrintSequence(out, seq.begin(), seq.end()); \
|
||||
return out; \
|
||||
}
|
||||
|
||||
INSTANTIATE_FOR_CONTAINER(std::vector)
|
||||
INSTANTIATE_FOR_CONTAINER(std::map)
|
||||
INSTANTIATE_FOR_CONTAINER(std::set)
|
||||
#undef INSTANTIATE_FOR_CONTAINER
|
||||
|
||||
template <class First, class Second>
|
||||
inline std::ostream& operator<<(
|
||||
std::ostream& out,
|
||||
const std::pair<First, Second>& p) {
|
||||
out << '(' << p.first << ", " << p.second << ')';
|
||||
return out;
|
||||
}
|
||||
|
||||
inline std::ostream& operator<<(
|
||||
std::ostream& out,
|
||||
const std::nullptr_t& /*unused*/) {
|
||||
out << "(null)";
|
||||
return out;
|
||||
}
|
||||
} // namespace std
|
||||
|
||||
namespace c10 {
|
||||
template <class Iter>
|
||||
inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
|
||||
// Output at most 100 elements -- appropriate if used for logging.
|
||||
for (int i = 0; begin != end && i < 100; ++i, ++begin) {
|
||||
if (i > 0)
|
||||
out << ' ';
|
||||
out << *begin;
|
||||
}
|
||||
if (begin != end) {
|
||||
out << " ...";
|
||||
}
|
||||
}
|
||||
} // namespace c10
|
||||
|
||||
#endif // C10_UTIL_LOGGING_IS_NOT_GOOGLE_GLOG_H_
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,46 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Export.h>
|
||||
#include <c10/util/Flags.h>
|
||||
#include <cstddef>
|
||||
|
||||
C10_DECLARE_bool(caffe2_cpu_numa_enabled);
|
||||
|
||||
namespace c10 {
|
||||
|
||||
/**
|
||||
* Check whether NUMA is enabled
|
||||
*/
|
||||
C10_API bool IsNUMAEnabled();
|
||||
|
||||
/**
|
||||
* Bind to a given NUMA node
|
||||
*/
|
||||
C10_API void NUMABind(int numa_node_id);
|
||||
|
||||
/**
|
||||
* Get the NUMA id for a given pointer `ptr`
|
||||
*/
|
||||
C10_API int GetNUMANode(const void* ptr);
|
||||
|
||||
/**
|
||||
* Get number of NUMA nodes
|
||||
*/
|
||||
C10_API int GetNumNUMANodes();
|
||||
|
||||
/**
|
||||
* Move the memory pointed to by `ptr` of a given size to another NUMA node
|
||||
*/
|
||||
C10_API void NUMAMove(void* ptr, size_t size, int numa_node_id);
|
||||
|
||||
/**
|
||||
* Get the current NUMA node id
|
||||
*/
|
||||
C10_API int GetCurrentNUMANode();
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
+2222
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <c10/macros/Macros.h>
|
||||
#include <c10/util/TypeSafeSignMath.h>
|
||||
#include <c10/util/complex.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <type_traits>
|
||||
|
||||
namespace c10 {
|
||||
// In some versions of MSVC, there will be a compiler error when building.
|
||||
// C4146: unary minus operator applied to unsigned type, result still unsigned
|
||||
// C4804: unsafe use of type 'bool' in operation
|
||||
// It can be addressed by disabling the following warning.
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4146)
|
||||
#pragma warning(disable : 4804)
|
||||
#pragma warning(disable : 4018)
|
||||
#endif
|
||||
|
||||
// The overflow checks may involve float to int conversion which may
|
||||
// trigger precision loss warning. Re-enable the warning once the code
|
||||
// is fixed. See T58053069.
|
||||
C10_CLANG_DIAGNOSTIC_PUSH()
|
||||
#if C10_CLANG_HAS_WARNING("-Wimplicit-float-conversion")
|
||||
C10_CLANG_DIAGNOSTIC_IGNORE("-Wimplicit-float-conversion")
|
||||
#endif
|
||||
|
||||
// bool can be converted to any type.
|
||||
// Without specializing on bool, in pytorch_linux_trusty_py2_7_9_build:
|
||||
// `error: comparison of constant '255' with boolean expression is always false`
|
||||
// for `f > limit::max()` below
|
||||
template <typename To, typename From>
|
||||
std::enable_if_t<std::is_same_v<From, bool>, bool> overflows(
|
||||
From /*f*/,
|
||||
bool strict_unsigned [[maybe_unused]] = false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// skip isnan and isinf check for integral types
|
||||
template <typename To, typename From>
|
||||
std::enable_if_t<std::is_integral_v<From> && !std::is_same_v<From, bool>, bool>
|
||||
overflows(From f, bool strict_unsigned = false) {
|
||||
using limit = std::numeric_limits<typename scalar_value_type<To>::type>;
|
||||
if constexpr (!limit::is_signed && std::numeric_limits<From>::is_signed) {
|
||||
// allow for negative numbers to wrap using two's complement arithmetic.
|
||||
// For example, with uint8, this allows for `a - b` to be treated as
|
||||
// `a + 255 * b`.
|
||||
if (!strict_unsigned) {
|
||||
return greater_than_max<To>(f) ||
|
||||
(c10::is_negative(f) &&
|
||||
-static_cast<uint64_t>(f) > static_cast<uint64_t>(limit::max()));
|
||||
}
|
||||
}
|
||||
return c10::less_than_lowest<To>(f) || greater_than_max<To>(f);
|
||||
}
|
||||
|
||||
template <typename To, typename From>
|
||||
std::enable_if_t<std::is_floating_point_v<From>, bool> overflows(
|
||||
From f,
|
||||
bool strict_unsigned [[maybe_unused]] = false) {
|
||||
using limit = std::numeric_limits<typename scalar_value_type<To>::type>;
|
||||
if (limit::has_infinity && std::isinf(static_cast<double>(f))) {
|
||||
return false;
|
||||
}
|
||||
if (!limit::has_quiet_NaN && (f != f)) {
|
||||
return true;
|
||||
}
|
||||
return f < limit::lowest() || f > limit::max();
|
||||
}
|
||||
|
||||
C10_CLANG_DIAGNOSTIC_POP()
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
template <typename To, typename From>
|
||||
std::enable_if_t<is_complex<From>::value, bool> overflows(
|
||||
From f,
|
||||
bool strict_unsigned = false) {
|
||||
// casts from complex to real are considered to overflow if the
|
||||
// imaginary component is non-zero
|
||||
if (!is_complex<To>::value && f.imag() != 0) {
|
||||
return true;
|
||||
}
|
||||
// Check for overflow componentwise
|
||||
// (Technically, the imag overflow check is guaranteed to be false
|
||||
// when !is_complex<To>, but any optimizer worth its salt will be
|
||||
// able to figure it out.)
|
||||
return overflows<
|
||||
typename scalar_value_type<To>::type,
|
||||
typename From::value_type>(f.real(), strict_unsigned) ||
|
||||
overflows<
|
||||
typename scalar_value_type<To>::type,
|
||||
typename From::value_type>(f.imag(), strict_unsigned);
|
||||
}
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,36 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
namespace c10 {
|
||||
namespace detail {
|
||||
|
||||
template <class... Ts>
|
||||
struct overloaded_t {};
|
||||
|
||||
template <class T0>
|
||||
struct overloaded_t<T0> : T0 {
|
||||
using T0::operator();
|
||||
overloaded_t(T0 t0) : T0(std::move(t0)) {}
|
||||
};
|
||||
template <class T0, class... Ts>
|
||||
struct overloaded_t<T0, Ts...> : T0, overloaded_t<Ts...> {
|
||||
using T0::operator();
|
||||
using overloaded_t<Ts...>::operator();
|
||||
overloaded_t(T0 t0, Ts... ts)
|
||||
: T0(std::move(t0)), overloaded_t<Ts...>(std::move(ts)...) {}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
// Construct an overloaded callable combining multiple callables, e.g. lambdas
|
||||
template <class... Ts>
|
||||
detail::overloaded_t<Ts...> overloaded(Ts... ts) {
|
||||
return {std::move(ts)...};
|
||||
}
|
||||
|
||||
} // namespace c10
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,9 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#pragma once
|
||||
|
||||
struct _object;
|
||||
using PyObject = _object;
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/qint32.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/qint8.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
@@ -0,0 +1,6 @@
|
||||
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
#include <torch/headeronly/util/quint2x4.h>
|
||||
|
||||
#else
|
||||
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
||||
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user