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 86b40856 [Fix][Rust] Serialize structural visit test registration
(#710)
86b40856 is described below
commit 86b40856a33c0bb3352311a409ddaf29d7eccd66
Author: Shushi Hong <[email protected]>
AuthorDate: Fri Aug 21 15:03:47 2026 -0400
[Fix][Rust] Serialize structural visit test registration (#710)
This pr fixes a flaky failure in the Rust structural visit tests.
The Rust test harness runs tests in parallel, and several independent
`LazyLock` initializers could register fixture types concurrently. The
runtime `TypeTable` intentionally does not synchronize updates and
requires registration callers to provide synchronization.
---
rust/tvm-ffi/tests/test_structural_visit.rs | 41 +++++++++++++----------------
1 file changed, 19 insertions(+), 22 deletions(-)
diff --git a/rust/tvm-ffi/tests/test_structural_visit.rs
b/rust/tvm-ffi/tests/test_structural_visit.rs
index c3069039..1c639b9b 100644
--- a/rust/tvm-ffi/tests/test_structural_visit.rs
+++ b/rust/tvm-ffi/tests/test_structural_visit.rs
@@ -216,7 +216,16 @@ fn registered_visit_hook(args: &[AnyView<'_>]) ->
Result<Any> {
.call_packed(&[args[0], AnyView::from(&node.data.selected)])
}
-static REGISTER_HOOK_TYPE: LazyLock<()> = LazyLock::new(|| {
+fn registered_primitive_visit_hook(args: &[AnyView<'_>]) -> Result<Any> {
+ assert_eq!(args.len(), 2);
+ Function::get_global("ffi.StructuralVisitorVisit")?
+ .call_packed(&[args[0], AnyView::from(&7i64)])
+}
+
+// The runtime type table leaves registration synchronization to its callers.
+// Run every fixture registration through one thread-safe initializer because
+// Rust tests execute in parallel.
+static REGISTER_TEST_TYPES: LazyLock<()> = LazyLock::new(|| {
let type_index = register_visit_type(
RustVisitHookObj::TYPE_KEY,
std::mem::size_of::<RustVisitHookObj>(),
@@ -239,9 +248,7 @@ static REGISTER_HOOK_TYPE: LazyLock<()> = LazyLock::new(|| {
"__s_visit__",
Function::from_packed(registered_visit_hook),
);
-});
-static REGISTER_FAILING_GETTER_TYPE: LazyLock<()> = LazyLock::new(|| {
let type_index = register_visit_type(
RustVisitFailingGetterObj::TYPE_KEY,
std::mem::size_of::<RustVisitFailingGetterObj>(),
@@ -261,23 +268,13 @@ static REGISTER_FAILING_GETTER_TYPE: LazyLock<()> =
LazyLock::new(|| {
field_static_type_index: -1,
};
assert_eq!(unsafe { TVMFFITypeRegisterField(type_index, &field) }, 0);
-});
-fn registered_primitive_visit_hook(args: &[AnyView<'_>]) -> Result<Any> {
- assert_eq!(args.len(), 2);
- Function::get_global("ffi.StructuralVisitorVisit")?
- .call_packed(&[args[0], AnyView::from(&7i64)])
-}
-
-static REGISTER_PRIMITIVE_HOOK: LazyLock<()> = LazyLock::new(|| {
register_function_attr(
TypeIndex::kTVMFFIDataType as i32,
"__s_visit__",
Function::from_packed(registered_primitive_visit_hook),
);
-});
-static REGISTER_REGION_TYPES: LazyLock<()> = LazyLock::new(|| {
let type_index = register_visit_type(
RustVisitDefRegionObj::TYPE_KEY,
std::mem::size_of::<RustVisitDefRegionObj>(),
@@ -315,12 +312,12 @@ static REGISTER_REGION_TYPES: LazyLock<()> =
LazyLock::new(|| {
}
});
-fn ensure_region_types_registered() {
- LazyLock::force(®ISTER_REGION_TYPES);
+fn test_prelude() {
+ LazyLock::force(®ISTER_TEST_TYPES);
}
fn rust_visit_hook(selected: impl Into<Any>, ignored: impl Into<Any>) ->
RustVisitHook {
- LazyLock::force(®ISTER_HOOK_TYPE);
+ test_prelude();
RustVisitHook {
data: ObjectArc::new(RustVisitHookObj {
base: Object::new(),
@@ -331,7 +328,7 @@ fn rust_visit_hook(selected: impl Into<Any>, ignored: impl
Into<Any>) -> RustVis
}
fn rust_visit_failing_getter(value: impl Into<Any>) -> RustVisitFailingGetter {
- LazyLock::force(®ISTER_FAILING_GETTER_TYPE);
+ test_prelude();
RustVisitFailingGetter {
data: ObjectArc::new(RustVisitFailingGetterObj {
base: Object::new(),
@@ -458,7 +455,7 @@ fn
registered_function_hook_controls_children_interrupts_and_lifetime() {
assert!(structural_visit(&root, &mut visitor).unwrap().is_none());
assert_eq!(visitor.integers, vec![11]);
- ensure_region_types_registered();
+ test_prelude();
let wrapped = RustVisitDefRegion {
data: ObjectArc::new(RustVisitDefRegionObj {
base: Object::new(),
@@ -508,7 +505,7 @@ fn
registered_function_hook_controls_children_interrupts_and_lifetime() {
#[test]
fn registered_hook_rejects_foreign_thread_visitor_callback() {
- LazyLock::force(®ISTER_HOOK_TYPE);
+ test_prelude();
RETAINED_VISITOR.with(|retained| {
retained.take();
});
@@ -535,7 +532,7 @@ fn
registered_hook_rejects_foreign_thread_visitor_callback() {
#[test]
fn primitive_hook_fast_path_preserves_pre_and_post_order() {
- LazyLock::force(®ISTER_PRIMITIVE_HOOK);
+ test_prelude();
let dtype = DLDataType::new(DLDataTypeCode::kDLFloat, 32, 1);
let mut pre = Vec::new();
@@ -1359,7 +1356,7 @@ fn def_region_is_inherited_through_containers() {
#[test]
fn reflected_field_def_region_reaches_typed_handler() {
- ensure_region_types_registered();
+ test_prelude();
let root = RustVisitDefRegion {
data: ObjectArc::new(RustVisitDefRegionObj {
base: Object::new(),
@@ -1435,7 +1432,7 @@ impl StructuralVisitor for FreeVarClampProbe {
#[test]
fn non_recursive_region_is_clamped_for_free_var_children_only() {
- ensure_region_types_registered();
+ test_prelude();
let free_var = RustVisitDefRegion {
data: ObjectArc::new(RustVisitDefRegionObj {
base: Object::new(),