main
py 74 lines 1.71 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """`LLMEngine`'s cleanup finalizer must not own the model.
4
5 ``weakref.finalize`` keeps its ``args`` strongly in a class-level registry
6 until it fires, and it only fires once the ``LLMEngine`` itself is collected.
7 Handing it the model directly therefore pins the weights -- and the KV cache
8 aliased onto the model's layers -- for as long as the engine is reachable,
9 which in-process is past engine shutdown.
10 """
11
12 import gc
13 import weakref
14
15 import pytest
16 import torch.nn as nn
17
18 from vllm.v1.engine.llm_engine import LLMEngine
19
20 pytestmark = pytest.mark.cpu_test
21
22
23 class _Model(nn.Module):
24 pass
25
26
27 def test_finalize_args_are_held_strongly():
28 """The premise: this is why the model must be passed weakly."""
29
30 class Owner:
31 pass
32
33 owner, model = Owner(), _Model()
34 weakref.finalize(owner, lambda _m: None, model)
35 ref = weakref.ref(model)
36
37 del model
38 gc.collect()
39
40 assert ref() is not None
41 del owner
42 gc.collect()
43 assert ref() is None
44
45
46 def test_cleanup_tolerates_a_dead_model():
47 model = _Model()
48 ref = weakref.ref(model)
49 del model
50 gc.collect()
51 assert ref() is None
52
53 LLMEngine._cleanup_instance_caches(ref)
54
55
56 def test_cleanup_still_walks_a_live_model(monkeypatch):
57 from vllm.compilation import wrapper
58
59 cleaned = []
60
61 class _FakeWrapper(nn.Module):
62 def cleanup(self):
63 cleaned.append(self)
64
65 monkeypatch.setattr(
66 wrapper, "TorchCompileWithNoGuardsWrapper", _FakeWrapper, raising=False
67 )
68
69 model = _Model()
70 model.inner = _FakeWrapper()
71
72 LLMEngine._cleanup_instance_caches(weakref.ref(model))
73
74 assert cleaned == [model.inner]