Skip to content

Commit 435caeb

Browse files
committed
[REFACTOR] Collapse custom-allocator setter API to single global entry point
Drop the unused per-type TVMFFISetCustomAllocator(int32_t,...) and rename TVMFFISetDefaultCustomAllocator to TVMFFISetCustomAllocator. Drop the type_index parameter from TVMFFIGetCustomAllocator since lookup no longer needs per-type resolution. The registry collapses to a single atomic; hot path becomes a single acquire load. Per-type opt-out for small heap-primitive types remains a clean future addition via a type-trait dispatched in Handler::New.
1 parent ab793e6 commit 435caeb

6 files changed

Lines changed: 39 additions & 82 deletions

File tree

include/tvm/ffi/c_api.h

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -622,8 +622,7 @@ typedef struct {
622622
} TVMFFICustomAllocHeader;
623623

624624
/*!
625-
* \brief Custom allocator entry registered with TVMFFISetCustomAllocator /
626-
* TVMFFISetDefaultCustomAllocator.
625+
* \brief Custom allocator entry registered with TVMFFISetCustomAllocator.
627626
*/
628627
typedef struct {
629628
/*!
@@ -638,36 +637,25 @@ typedef struct {
638637
} TVMFFICustomAllocator;
639638

640639
/*!
641-
* \brief Get the custom allocator registered for ``type_index``.
640+
* \brief Get the process-wide custom allocator.
642641
*
643-
* Resolution order: per-type slot (if non-NULL) -> global default allocator
644-
* -> NULL (no custom allocator; caller takes the default malloc path).
642+
* libtvm_ffi installs a builtin default at registry init, so the result is
643+
* never NULL in practice. Frontends can override the global allocator via
644+
* TVMFFISetCustomAllocator.
645645
*
646-
* \param type_index The type index of the Object being allocated, or -1 to
647-
* query the global default directly.
648-
* \return The allocator, or NULL when none is registered.
646+
* \return The currently registered allocator.
649647
*/
650-
TVM_FFI_DLL TVMFFICustomAllocator* TVMFFIGetCustomAllocator(int32_t type_index);
648+
TVM_FFI_DLL TVMFFICustomAllocator* TVMFFIGetCustomAllocator(void);
651649

652650
/*!
653-
* \brief Register an allocator for a specific type index. Pass
654-
* ``allocator==NULL`` to clear the slot and fall back to the global
655-
* default.
651+
* \brief Register the process-wide custom allocator. Pass ``allocator==NULL``
652+
* to restore the builtin default.
656653
*
657-
* \param type_index The type index whose slot is being installed.
658-
* \param allocator Pointer to a TVMFFICustomAllocator with process-stable
659-
* lifetime.
654+
* \param allocator Pointer to a TVMFFICustomAllocator with process-stable
655+
* lifetime, or NULL to reset to the builtin default.
660656
* \return 0 on success, nonzero on failure.
661657
*/
662-
TVM_FFI_DLL int TVMFFISetCustomAllocator(int32_t type_index, TVMFFICustomAllocator* allocator);
663-
664-
/*!
665-
* \brief Register a process-wide default allocator used for any type without
666-
* a per-type override. Pass ``allocator==NULL`` to clear it.
667-
*
668-
* \return 0 on success, nonzero on failure.
669-
*/
670-
TVM_FFI_DLL int TVMFFISetDefaultCustomAllocator(TVMFFICustomAllocator* allocator);
658+
TVM_FFI_DLL int TVMFFISetCustomAllocator(TVMFFICustomAllocator* allocator);
671659

672660
/*!
673661
* \brief Convert type key to type index.

include/tvm/ffi/memory.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,8 @@ class ObjAllocatorBase {
148148
// never null and every Object always has a TVMFFICustomAllocHeader
149149
// sitting immediately before it. Frontends with richer per-allocation
150150
// bookkeeping (e.g. Python's PyCustomAllocHeader) override the global
151-
// default with their own allocator.
152-
TVMFFICustomAllocator* alloc = TVMFFIGetCustomAllocator(T::RuntimeTypeIndex());
151+
// allocator with their own.
152+
TVMFFICustomAllocator* alloc = TVMFFIGetCustomAllocator();
153153
T* ptr = Handler::New(static_cast<Derived*>(this), alloc, std::forward<Args>(args)...);
154154
TVMFFIObject* ffi_ptr = details::ObjectUnsafe::GetHeader(ptr);
155155
ffi_ptr->combined_ref_count = kCombinedRefCountBothOne;
@@ -171,7 +171,7 @@ class ObjAllocatorBase {
171171
using Handler = typename Derived::template ArrayHandler<ArrayType, ElemType>;
172172
static_assert(std::is_base_of_v<Object, ArrayType>,
173173
"make_inplace_array can only be used to create Object");
174-
TVMFFICustomAllocator* alloc = TVMFFIGetCustomAllocator(ArrayType::RuntimeTypeIndex());
174+
TVMFFICustomAllocator* alloc = TVMFFIGetCustomAllocator();
175175
ArrayType* ptr = Handler::New(static_cast<Derived*>(this), alloc, num_elems,
176176
std::forward<Args>(args)...);
177177
TVMFFIObject* ffi_ptr = details::ObjectUnsafe::GetHeader(ptr);

python/tvm_ffi/cython/base.pxi

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,8 @@ cdef extern from "tvm/ffi/c_api.h":
173173
ctypedef struct TVMFFICustomAllocator:
174174
void* (*allocate)(size_t size, size_t alignment, int32_t type_index)
175175

176-
TVMFFICustomAllocator* TVMFFIGetCustomAllocator(int32_t type_index) nogil
177-
int TVMFFISetCustomAllocator(int32_t type_index, TVMFFICustomAllocator* allocator) nogil
178-
int TVMFFISetDefaultCustomAllocator(TVMFFICustomAllocator* allocator) nogil
176+
TVMFFICustomAllocator* TVMFFIGetCustomAllocator() nogil
177+
int TVMFFISetCustomAllocator(TVMFFICustomAllocator* allocator) nogil
179178

180179
ctypedef struct TVMFFIAny:
181180
int32_t type_index

python/tvm_ffi/cython/tvm_ffi_python_helpers.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ TVM_FFI_INLINE PyCustomAllocHeader* TVMFFIPyHeader(void* tptr) {
151151
inline void TVMFFIPyDeleteSpace(void* tptr);
152152

153153
/*!
154-
* \brief Allocator entry registered with TVMFFISetDefaultCustomAllocator at
154+
* \brief Allocator entry registered with TVMFFISetCustomAllocator at
155155
* Cython module init. Allocates ``kPyHeaderOffset + size`` bytes,
156156
* zero-inits the prepended PyCustomAllocHeader (in particular
157157
* ``py_object = NULL``), wires ``base.delete_space`` to
@@ -201,7 +201,7 @@ inline void TVMFFIPyDeleteSpace(void* tptr) {
201201
*/
202202
TVM_FFI_INLINE int TVMFFIPyRegisterDefaultAllocator() {
203203
static TVMFFICustomAllocator allocator{&TVMFFIPyAllocate};
204-
return TVMFFISetDefaultCustomAllocator(&allocator);
204+
return TVMFFISetCustomAllocator(&allocator);
205205
}
206206

207207
/*!

src/ffi/custom_allocator.cc

Lines changed: 18 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@
1818
*/
1919
/*
2020
* \file src/ffi/custom_allocator.cc
21-
* \brief Process-wide registry for custom Object allocators.
21+
* \brief Process-wide registry for the custom Object allocator.
2222
*
2323
* Every Object allocation goes through the registered allocator. libtvm_ffi
2424
* installs a builtin default allocator (BuiltinDefaultAllocate / DeleteSpace)
2525
* at registry construction so the hot path is never null and every Object
2626
* carries at least the base TVMFFICustomAllocHeader. Frontends (Python via
2727
* the Cython extension, future Rust binding, etc.) override the global
28-
* default with TVMFFISetDefaultCustomAllocator when they need richer
28+
* allocator with TVMFFISetCustomAllocator when they need richer
2929
* per-allocation bookkeeping.
3030
*/
3131
#include <tvm/ffi/base_details.h>
@@ -35,10 +35,7 @@
3535

3636
#include <atomic>
3737
#include <cstdlib>
38-
#include <cstring>
39-
#include <mutex>
4038
#include <new>
41-
#include <unordered_map>
4239

4340
namespace tvm {
4441
namespace ffi {
@@ -114,39 +111,16 @@ class CustomAllocatorRegistry {
114111
// Install the builtin default at construction so the very first
115112
// Object allocation in the process (e.g. inside a static initializer
116113
// that registers a global function) finds a usable allocator.
117-
static TVMFFICustomAllocator builtin{&BuiltinDefaultAllocate};
118-
default_.store(&builtin, std::memory_order_release);
114+
current_.store(BuiltinDefault(), std::memory_order_release);
119115
}
120116

121-
TVMFFICustomAllocator* Get(int32_t idx) const {
122-
// Hot path: when no per-type override has been registered, skip the
123-
// mutex entirely and just read the global default. The size counter is
124-
// incremented under mu_ before the first per-type entry is visible, so
125-
// an acquire load here pairs with the release store in Set.
126-
if (per_type_size_.load(std::memory_order_acquire) == 0) {
127-
return default_.load(std::memory_order_acquire);
128-
}
129-
if (idx >= 0) {
130-
std::lock_guard<std::mutex> g(mu_);
131-
auto it = per_type_.find(idx);
132-
if (it != per_type_.end()) return it->second;
133-
}
134-
return default_.load(std::memory_order_acquire);
117+
TVMFFICustomAllocator* Get() const {
118+
return current_.load(std::memory_order_acquire);
135119
}
136120

137-
void Set(int32_t idx, TVMFFICustomAllocator* allocator) {
138-
if (idx < 0) return;
139-
std::lock_guard<std::mutex> g(mu_);
140-
if (allocator != nullptr) {
141-
per_type_[idx] = allocator;
142-
} else {
143-
per_type_.erase(idx);
144-
}
145-
per_type_size_.store(per_type_.size(), std::memory_order_release);
146-
}
147-
148-
void SetDefault(TVMFFICustomAllocator* allocator) {
149-
default_.store(allocator, std::memory_order_release);
121+
void Set(TVMFFICustomAllocator* allocator) {
122+
current_.store(allocator != nullptr ? allocator : BuiltinDefault(),
123+
std::memory_order_release);
150124
}
151125

152126
static CustomAllocatorRegistry* Global() {
@@ -155,30 +129,26 @@ class CustomAllocatorRegistry {
155129
}
156130

157131
private:
158-
std::atomic<TVMFFICustomAllocator*> default_{nullptr};
159-
std::atomic<size_t> per_type_size_{0};
160-
mutable std::mutex mu_;
161-
std::unordered_map<int32_t, TVMFFICustomAllocator*> per_type_;
132+
static TVMFFICustomAllocator* BuiltinDefault() {
133+
static TVMFFICustomAllocator builtin{&BuiltinDefaultAllocate};
134+
return &builtin;
135+
}
136+
137+
std::atomic<TVMFFICustomAllocator*> current_{nullptr};
162138
};
163139

164140
} // namespace
165141
} // namespace ffi
166142
} // namespace tvm
167143

168-
TVMFFICustomAllocator* TVMFFIGetCustomAllocator(int32_t type_index) {
144+
TVMFFICustomAllocator* TVMFFIGetCustomAllocator(void) {
169145
TVM_FFI_LOG_EXCEPTION_CALL_BEGIN();
170-
return tvm::ffi::CustomAllocatorRegistry::Global()->Get(type_index);
146+
return tvm::ffi::CustomAllocatorRegistry::Global()->Get();
171147
TVM_FFI_LOG_EXCEPTION_CALL_END(TVMFFIGetCustomAllocator);
172148
}
173149

174-
int TVMFFISetCustomAllocator(int32_t type_index, TVMFFICustomAllocator* allocator) {
175-
TVM_FFI_SAFE_CALL_BEGIN();
176-
tvm::ffi::CustomAllocatorRegistry::Global()->Set(type_index, allocator);
177-
TVM_FFI_SAFE_CALL_END();
178-
}
179-
180-
int TVMFFISetDefaultCustomAllocator(TVMFFICustomAllocator* allocator) {
150+
int TVMFFISetCustomAllocator(TVMFFICustomAllocator* allocator) {
181151
TVM_FFI_SAFE_CALL_BEGIN();
182-
tvm::ffi::CustomAllocatorRegistry::Global()->SetDefault(allocator);
152+
tvm::ffi::CustomAllocatorRegistry::Global()->Set(allocator);
183153
TVM_FFI_SAFE_CALL_END();
184154
}

src/ffi/extra/dataclass.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2051,7 +2051,7 @@ void PyClassRegisterTypeAttrColumns(int32_t type_index, int32_t total_size) {
20512051
// Both are valid initial states whose destructors / assignment
20522052
// operators handle correctly, so no placement construction is needed.
20532053
size_t alloc_size = static_cast<size_t>(total_size);
2054-
TVMFFICustomAllocator* alloc = TVMFFIGetCustomAllocator(type_index);
2054+
TVMFFICustomAllocator* alloc = TVMFFIGetCustomAllocator();
20552055
void* obj_ptr = alloc->allocate(alloc_size, alignof(::std::max_align_t), type_index);
20562056
std::memset(obj_ptr, 0, alloc_size);
20572057
TVMFFIObject* ffi_obj = reinterpret_cast<TVMFFIObject*>(obj_ptr);
@@ -2070,7 +2070,7 @@ void PyClassRegisterTypeAttrColumns(int32_t type_index, int32_t total_size) {
20702070
Function::FromTyped([type_index, total_size, type_info](const Object* src) -> ObjectRef {
20712071
// Mirror RegisterFFINew above.
20722072
size_t alloc_size = static_cast<size_t>(total_size);
2073-
TVMFFICustomAllocator* alloc = TVMFFIGetCustomAllocator(type_index);
2073+
TVMFFICustomAllocator* alloc = TVMFFIGetCustomAllocator();
20742074
void* obj_ptr = alloc->allocate(alloc_size, alignof(::std::max_align_t), type_index);
20752075
std::memset(obj_ptr, 0, alloc_size);
20762076
TVMFFIObject* ffi_obj = reinterpret_cast<TVMFFIObject*>(obj_ptr);

0 commit comments

Comments
 (0)