This is an automated email from the ASF dual-hosted git repository.
tqchen pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-ffi.git
The following commit(s) were added to refs/heads/main by this push:
new 9844079 [OBJECT] Optimize dynamic RuntimeTypeIndex loads (#634)
9844079 is described below
commit 98440793acb46f35c7611315df2e187195249605
Author: Tianqi Chen <[email protected]>
AuthorDate: Thu Jun 18 15:48:03 2026 -0400
[OBJECT] Optimize dynamic RuntimeTypeIndex loads (#634)
This PR caches dynamically allocated object type indices in a static
inline const `_type_index` and makes `RuntimeTypeIndex` return the
cached value directly. `_GetOrAllocRuntimeTypeIndex` is marked cold and
moves to cold/startup code, reducing the hot accessor to a plain load.
Side codegen probe for a dynamic object accessor:
- `ReadDynTypeIndex`: 176 B -> 14 B
- total probe object: 769 B -> 634 B
- hot path no longer contains function-local static guard/allocation
checks
- added static inline storage cost is explicit: 4 B `_type_index`, 8 B
guard, 8 B `.init_array`, plus small startup init
---
include/tvm/ffi/enum.h | 8 +++++---
include/tvm/ffi/object.h | 13 +++++++------
include/tvm/ffi/reflection/enum_def.h | 9 +++++----
include/tvm/ffi/reflection/registry.h | 2 +-
4 files changed, 18 insertions(+), 14 deletions(-)
diff --git a/include/tvm/ffi/enum.h b/include/tvm/ffi/enum.h
index 0cd97d9..a42a182 100644
--- a/include/tvm/ffi/enum.h
+++ b/include/tvm/ffi/enum.h
@@ -131,16 +131,18 @@ inline Enum EnumObj::Get(const String& name) {
static_assert(std::is_base_of_v<EnumObj, EnumClsObj>,
"EnumObj::Get<T> requires T to be a subclass of EnumObj");
const TVMFFITypeAttrColumn* column = GetEnumEntriesColumn();
- int32_t type_index = EnumClsObj::RuntimeTypeIndex();
+ int32_t type_index = EnumClsObj::_GetOrAllocRuntimeTypeIndex();
if (column != nullptr) {
int32_t offset = type_index - column->begin_index;
if (offset >= 0 && offset < column->size) {
const TVMFFIAny* stored = &column->data[offset];
if (stored->type_index != kTVMFFINone) {
- Dict<String, Enum> entries =
AnyView::CopyFromTVMFFIAny(*stored).cast<Dict<String, Enum>>();
+ Dict<String, ObjectRef> entries =
+ AnyView::CopyFromTVMFFIAny(*stored).cast<Dict<String,
ObjectRef>>();
auto it = entries.find(name);
if (it != entries.end()) {
- return (*it).second;
+ return details::ObjectUnsafe::ObjectRefFromObjectPtr<Enum>(
+
details::ObjectUnsafe::ObjectPtrFromObjectRef<EnumObj>((*it).second));
}
}
}
diff --git a/include/tvm/ffi/object.h b/include/tvm/ffi/object.h
index 262c570..71c69f1 100644
--- a/include/tvm/ffi/object.h
+++ b/include/tvm/ffi/object.h
@@ -307,11 +307,11 @@ class Object {
* \brief Get the runtime allocated type index of the type
* \note Getting this information may need dynamic calls into a global table.
*/
- static int32_t RuntimeTypeIndex() { return TypeIndex::kTVMFFIObject; }
+ TVM_FFI_INLINE static int32_t RuntimeTypeIndex() noexcept { return
TypeIndex::kTVMFFIObject; }
/*!
* \brief Internal function to get or allocate a runtime index.
*/
- static int32_t _GetOrAllocRuntimeTypeIndex() { //
NOLINT(bugprone-reserved-identifier)
+ TVM_FFI_COLD_CODE static int32_t _GetOrAllocRuntimeTypeIndex() { //
NOLINT(*)
return TypeIndex::kTVMFFIObject;
}
@@ -936,7 +936,7 @@ struct ObjectPtrEqual {
*/
#define TVM_FFI_DECLARE_OBJECT_INFO_STATIC(TypeKey, TypeName, ParentType)
\
static constexpr int32_t _type_depth = ParentType::_type_depth + 1;
\
- static int32_t _GetOrAllocRuntimeTypeIndex() {
\
+ TVM_FFI_COLD_CODE static int32_t _GetOrAllocRuntimeTypeIndex() {
\
static_assert(!ParentType::_type_final, "ParentType marked as final");
\
static_assert(TypeName::_type_child_slots == 0 ||
ParentType::_type_child_slots == 0 || \
TypeName::_type_child_slots <
ParentType::_type_child_slots, \
@@ -948,7 +948,7 @@ struct ObjectPtrEqual {
TypeName::_type_child_slots_can_overflow,
ParentType::_GetOrAllocRuntimeTypeIndex()); \
return TypeName::_type_index;
\
}
\
- static int32_t RuntimeTypeIndex() { return TypeName::_type_index; }
\
+ TVM_FFI_INLINE static int32_t RuntimeTypeIndex() noexcept { return
TypeName::_type_index; } \
static constexpr const char* _type_key = TypeKey
/*!
@@ -959,7 +959,7 @@ struct ObjectPtrEqual {
*/
#define TVM_FFI_DECLARE_OBJECT_INFO_PREDEFINED_TYPE_KEY(TypeName, ParentType)
\
static constexpr int32_t _type_depth = ParentType::_type_depth + 1;
\
- static int32_t _GetOrAllocRuntimeTypeIndex() {
\
+ TVM_FFI_COLD_CODE static int32_t _GetOrAllocRuntimeTypeIndex() {
\
static_assert(!ParentType::_type_final, "ParentType marked as final");
\
static_assert(TypeName::_type_child_slots == 0 ||
ParentType::_type_child_slots == 0 || \
TypeName::_type_child_slots <
ParentType::_type_child_slots, \
@@ -971,7 +971,8 @@ struct ObjectPtrEqual {
TypeName::_type_child_slots_can_overflow,
ParentType::_GetOrAllocRuntimeTypeIndex()); \
return tindex;
\
}
\
- static int32_t RuntimeTypeIndex() { return _GetOrAllocRuntimeTypeIndex(); }
+ static inline const int32_t _type_index =
TypeName::_GetOrAllocRuntimeTypeIndex(); \
+ TVM_FFI_INLINE static int32_t RuntimeTypeIndex() noexcept { return
TypeName::_type_index; }
/*!
* \brief Helper macro to declare object information with dynamic type index.
diff --git a/include/tvm/ffi/reflection/enum_def.h
b/include/tvm/ffi/reflection/enum_def.h
index 6e1e91c..1970d24 100644
--- a/include/tvm/ffi/reflection/enum_def.h
+++ b/include/tvm/ffi/reflection/enum_def.h
@@ -74,8 +74,8 @@ class EnumDef : public ReflectionDefBase {
* \param instance_name The instance's string name (e.g., ``"Add"``).
*/
explicit EnumDef(const char* instance_name)
- : type_index_(EnumClsObj::RuntimeTypeIndex()), name_(instance_name) {
- Dict<String, Enum> entries = EnsureEntriesDict();
+ : type_index_(EnumClsObj::_GetOrAllocRuntimeTypeIndex()),
name_(instance_name) {
+ Dict<String, ObjectRef> entries = EnsureEntriesDict();
String name_str(name_);
if (entries.count(name_str) != 0) {
TVM_FFI_THROW(RuntimeError) << "Duplicate enum entry `" << name_ << "`
for type `"
@@ -83,6 +83,7 @@ class EnumDef : public ReflectionDefBase {
}
ordinal_ = static_cast<int64_t>(entries.size());
ObjectPtr<EnumClsObj> obj = make_object<EnumClsObj>();
+ ::tvm::ffi::details::ObjectUnsafe::GetHeader(obj.get())->type_index =
type_index_;
obj->_value = ordinal_;
obj->_name = name_str;
instance_ = Enum(ObjectPtr<EnumObj>(std::move(obj)));
@@ -134,8 +135,8 @@ class EnumDef : public ReflectionDefBase {
int64_t ordinal() const { return ordinal_; }
private:
- Dict<String, Enum> EnsureEntriesDict() {
- return EnsureDict<Dict<String, Enum>>(type_attr::kEnumEntries);
+ Dict<String, ObjectRef> EnsureEntriesDict() {
+ return EnsureDict<Dict<String, ObjectRef>>(type_attr::kEnumEntries);
}
Dict<String, List<Any>> EnsureAttrsDict() {
diff --git a/include/tvm/ffi/reflection/registry.h
b/include/tvm/ffi/reflection/registry.h
index f810e5f..2acdce7 100644
--- a/include/tvm/ffi/reflection/registry.h
+++ b/include/tvm/ffi/reflection/registry.h
@@ -992,7 +992,7 @@ class TypeAttrDef : public ReflectionDefBase {
*/
template <typename... ExtraArgs>
explicit TypeAttrDef(ExtraArgs&&... extra_args)
- : type_index_(Class::RuntimeTypeIndex()), type_key_(Class::_type_key) {}
+ : type_index_(Class::_GetOrAllocRuntimeTypeIndex()),
type_key_(Class::_type_key) {}
/*!
* \brief Define a function-valued type attribute.