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

This commit is contained in:
Kolp
2026-09-24 13:22:23 +07:00
commit 642cc11a9f
18968 changed files with 5683248 additions and 0 deletions
@@ -0,0 +1,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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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