Skip to content

Conversation

@tqchen
Copy link
Member

@tqchen tqchen commented Aug 31, 2025

This PR adds weak ref counter support to the FFI ABI. Weak rc is useful when we want to break cyclic dependencies.

  • When a strong rc goes to zero, we call the destructor of the object, but not freeing the memory
  • When both strong and weak rc goes to zero, we call the memory free operation

The weak rc mechanism is useful when we want to break cyclic dependencies in object, where the weak rc can keep memory alive but the destructor is called. As of now, because we deliberately avoid cyles in codebase, we do not have strong use-case for weak rc.

However, given weak rc is common practice in shared_ptr, Rust RC, and also used in torch's intrusive_ptr. It is better to make sure the ABI is future compatible to such use-cases before we freeze.

This PR implements weak rc as a u32 counter and strong rc as a u64 counter, with the following design consideration.

  • Weak rc is very rarely used and u32 is sufficient.
  • Keeping weak rc in u32 allows us to keep object header size to 24 bytes, saving extra 8 bytes(considering alignment)

We also need to update deleter to take flags that consider both weak and strong deletion events. The implementation tries to optimize common case where both strong and weak goes to 0 at the same time and call deleter once with both flags set.

@tqchen tqchen force-pushed the weak-rc branch 4 times, most recently from 762de31 to 685aa85 Compare August 31, 2025 21:48
This PR adds weak ref counter support to the FFI ABI.
Weak rc is useful when we want to break cyclic dependencies.

- When a strong rc goes to zero, we call the destructor of the object, but not freeing the memory
- When both strong and weak rc goes to zero, we call the memory free operation

The weak rc mechanism is useful when we want to break cyclic dependencies in object, where the
weak rc can keep memory alive but the destructor is called.
As of now, because we deliberately avoid cyles in codebase, we do not have strong use-case for weak rc.

However, given weak rc is common practice in shared_ptr, Rust RC, and also used in torch's c10::intrusive_ptr.
It is better to make sure the ABI is future compatible to such use-cases before we freeze.

This PR implements weak rc as a u32 counter and strong rc as a u64 counter, with the following
design consideration.

- Weak rc is very rarely used and u32 is sufficient.
- Keeping weak rc in u32 allows us to keep object header size to 24 bytes,
  saving extra 8 bytes(considering alignment)

We also need to update deleter to take flags that consider both weak and
strong deletion events. The implementation tries to optimize common case where
both strong and weak goes to 0 at the same time and call deleter once
with both flags set.
@yongwww
Copy link
Member

yongwww commented Sep 1, 2025

@tvm-bot rerun

@mshr-h mshr-h merged commit 46eac56 into apache:main Sep 1, 2025
13 checks passed
tqchen added a commit to tqchen/tvm that referenced this pull request Sep 13, 2025
This PR adds weak ref counter support to the FFI ABI.
Weak rc is useful when we want to break cyclic dependencies.

- When a strong rc goes to zero, we call the destructor of the object, but not freeing the memory
- When both strong and weak rc goes to zero, we call the memory free operation

The weak rc mechanism is useful when we want to break cyclic dependencies in object, where the
weak rc can keep memory alive but the destructor is called.
As of now, because we deliberately avoid cyles in codebase, we do not have strong use-case for weak rc.

However, given weak rc is common practice in shared_ptr, Rust RC, and also used in torch's c10::intrusive_ptr.
It is better to make sure the ABI is future compatible to such use-cases before we freeze.

This PR implements weak rc as a u32 counter and strong rc as a u64 counter, with the following
design consideration.

- Weak rc is very rarely used and u32 is sufficient.
- Keeping weak rc in u32 allows us to keep object header size to 24 bytes,
  saving extra 8 bytes(considering alignment)

We also need to update deleter to take flags that consider both weak and
strong deletion events. The implementation tries to optimize common case where
both strong and weak goes to 0 at the same time and call deleter once
with both flags set.
tqchen added a commit to tqchen/tvm that referenced this pull request Sep 13, 2025
This PR adds weak ref counter support to the FFI ABI.
Weak rc is useful when we want to break cyclic dependencies.

- When a strong rc goes to zero, we call the destructor of the object, but not freeing the memory
- When both strong and weak rc goes to zero, we call the memory free operation

The weak rc mechanism is useful when we want to break cyclic dependencies in object, where the
weak rc can keep memory alive but the destructor is called.
As of now, because we deliberately avoid cyles in codebase, we do not have strong use-case for weak rc.

However, given weak rc is common practice in shared_ptr, Rust RC, and also used in torch's c10::intrusive_ptr.
It is better to make sure the ABI is future compatible to such use-cases before we freeze.

This PR implements weak rc as a u32 counter and strong rc as a u64 counter, with the following
design consideration.

- Weak rc is very rarely used and u32 is sufficient.
- Keeping weak rc in u32 allows us to keep object header size to 24 bytes,
  saving extra 8 bytes(considering alignment)

We also need to update deleter to take flags that consider both weak and
strong deletion events. The implementation tries to optimize common case where
both strong and weak goes to 0 at the same time and call deleter once
with both flags set.
tqchen added a commit to tqchen/tvm that referenced this pull request Sep 13, 2025
This PR adds weak ref counter support to the FFI ABI.
Weak rc is useful when we want to break cyclic dependencies.

- When a strong rc goes to zero, we call the destructor of the object, but not freeing the memory
- When both strong and weak rc goes to zero, we call the memory free operation

The weak rc mechanism is useful when we want to break cyclic dependencies in object, where the
weak rc can keep memory alive but the destructor is called.
As of now, because we deliberately avoid cyles in codebase, we do not have strong use-case for weak rc.

However, given weak rc is common practice in shared_ptr, Rust RC, and also used in torch's c10::intrusive_ptr.
It is better to make sure the ABI is future compatible to such use-cases before we freeze.

This PR implements weak rc as a u32 counter and strong rc as a u64 counter, with the following
design consideration.

- Weak rc is very rarely used and u32 is sufficient.
- Keeping weak rc in u32 allows us to keep object header size to 24 bytes,
  saving extra 8 bytes(considering alignment)

We also need to update deleter to take flags that consider both weak and
strong deletion events. The implementation tries to optimize common case where
both strong and weak goes to 0 at the same time and call deleter once
with both flags set.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants