### Motivation
`tvm.testing` imports `pytest` at module load (`tvm/testing/utils.py`).
`tvm.rpc.server` imports `tvm.rpc.testing` (to register the `rpc.test.*`
helpers), and `tvm.rpc.testing` imported `tvm.testing` at the top level,
so a plain `import tvm` / `import tvm.relax` pulls `pytest` in through:
```
tvm.relax -> tvm.runtime.vm -> tvm.rpc -> rpc.server -> rpc.testing -> tvm.testing -> pytest
```
As a result `pytest` is effectively a runtime dependency: a user who
installs TVM without `pytest` hits `ModuleNotFoundError: No module named
'pytest'` on import. This is easy to miss because test environments
install `pytest`.
### Change
`tvm.rpc.testing` only uses `tvm.testing.object_use_count` in a single
test helper, so import it lazily at the call site instead of at module
top level. This keeps the `rpc.test.*` registration and the helper
behavior intact while removing `tvm.testing` (and `pytest`) from the
`import tvm` path, so `pytest` can remain a test-only dependency.
No functional change; `rpc.testing` is still imported by `rpc.server`
and still registers the same global functions.
This PR fixes RPC tensor cleanup for tensors returned from remote calls.
When a remote function returns a `Tensor`, the RPC protocol sends both:
- the remote backing data pointer
- the remote tensor object handle used for deletion
Previously, `TensorFromRemoteOpaqueHandle` stored only the data pointer
and called
`FreeHandle(space_.data)` during local tensor destruction. That is
incorrect:
`FreeHandle` is meant for remote object handles, not raw data-space
pointers.
This could lead to invalid cleanup behavior and crashes during teardown
in RPC workflows, including the cross-compilation + RPC tutorial
scenario reported in #18923.
This change:
- stores the remote tensor object handle in `RemoteSpace`
- calls `FreeHandle(remote_tensor_handle)` during tensor destruction
- keeps cleanup fault-tolerant if the remote connection is already
closed
This PR cleans up the python API to make things more consistent
with existing python array api and torch.
Device update
- device_id => index, to be consistent with torch
- device_type => dlpack_device_type() returns int
- added type property same as torch.device
API updates:
- Move the convenient method like cpu() out into tvm runtime to keep device minimal
- tvm_ffi._init_api => tvm_ffi.init_ffi_api
- tvm_ffi.register_func => tvm_ffi.register_global_func
This PR Updates the NDArray => Tensor.
Both tensor and ndarray are commonly used terms.
Because the term Tensor is getting more common in the context of ML,
we do the rename to stay more aligned with torch.Tensor and DLTensor.
Previously the rpc server relies multiprocessing to start a new process and does not work under jupyter.
It also have a popen mode that does ensure the socket start listening before returning the port number.
This PR switches the implementations use PopenWorker. The port number is returned after the socket
get binded, which resolves some of the RPC flaky issues(need sleep to wait the server to start).
It also makes the RPC server jupyter friendly.