test_utils.py 4.26 KB
Newer Older
1
import pytest
2
import ray
3
import torch
4

5
import vllm.envs as envs
6
7
from vllm.distributed.device_communicators.pynccl import PyNcclCommunicator
from vllm.distributed.utils import StatelessProcessGroup
8
from vllm.utils import (cuda_device_count_stateless,
9
                        update_environment_variables)
10

11
12
from ..utils import multi_gpu_test

13
14

@ray.remote
15
class _CUDADeviceCountStatelessTestActor:
16
17
18
19
20

    def get_count(self):
        return cuda_device_count_stateless()

    def set_cuda_visible_devices(self, cuda_visible_devices: str):
21
22
        update_environment_variables(
            {"CUDA_VISIBLE_DEVICES": cuda_visible_devices})
23
24

    def get_cuda_visible_devices(self):
25
        return envs.CUDA_VISIBLE_DEVICES
26
27
28
29
30


def test_cuda_device_count_stateless():
    """Test that cuda_device_count_stateless changes return value if
    CUDA_VISIBLE_DEVICES is changed."""
31
32
    actor = _CUDADeviceCountStatelessTestActor.options(  # type: ignore
        num_gpus=2).remote()
33
34
35
    assert len(
        sorted(ray.get(
            actor.get_cuda_visible_devices.remote()).split(","))) == 2
36
37
38
39
40
    assert ray.get(actor.get_count.remote()) == 2
    ray.get(actor.set_cuda_visible_devices.remote("0"))
    assert ray.get(actor.get_count.remote()) == 1
    ray.get(actor.set_cuda_visible_devices.remote(""))
    assert ray.get(actor.get_count.remote()) == 0
41
42
43


def cpu_worker(rank, WORLD_SIZE):
44
    pg1 = StatelessProcessGroup.create(init_method="tcp://127.0.0.1:29500",
45
                                       rank=rank,
46
                                       world_size=WORLD_SIZE)
47
    if rank <= 2:
48
        pg2 = StatelessProcessGroup.create(init_method="tcp://127.0.0.1:29501",
49
                                           rank=rank,
50
                                           world_size=3)
51
    data = torch.tensor([rank])
52
53
    data = pg1.broadcast_obj(data, src=2)
    assert data.item() == 2
54
    if rank <= 2:
55
56
57
58
59
        data = torch.tensor([rank + 1])
        data = pg2.broadcast_obj(data, src=2)
        assert data.item() == 3
        pg2.barrier()
    pg1.barrier()
60
61
62


def gpu_worker(rank, WORLD_SIZE):
63
64
    torch.cuda.set_device(rank)
    pg1 = StatelessProcessGroup.create(init_method="tcp://127.0.0.1:29502",
65
                                       rank=rank,
66
67
68
                                       world_size=WORLD_SIZE)
    pynccl1 = PyNcclCommunicator(pg1, device=rank)
    pynccl1.disabled = False
69
    if rank <= 2:
70
        pg2 = StatelessProcessGroup.create(init_method="tcp://127.0.0.1:29503",
71
                                           rank=rank,
72
73
74
                                           world_size=3)
        pynccl2 = PyNcclCommunicator(pg2, device=rank)
        pynccl2.disabled = False
75
    data = torch.tensor([rank]).cuda()
76
77
78
    pynccl1.all_reduce(data)
    pg1.barrier()
    torch.cuda.synchronize()
79
    if rank <= 2:
80
81
82
        pynccl2.all_reduce(data)
        pg2.barrier()
        torch.cuda.synchronize()
83
84
85
86
87
88
89
90
    item = data[0].item()
    print(f"rank: {rank}, item: {item}")
    if rank == 3:
        assert item == 6
    else:
        assert item == 18


91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
def broadcast_worker(rank, WORLD_SIZE):
    pg1 = StatelessProcessGroup.create(init_method="tcp://127.0.0.1:29504",
                                       rank=rank,
                                       world_size=WORLD_SIZE)
    if rank == 2:
        pg1.broadcast_obj("secret", src=2)
    else:
        obj = pg1.broadcast_obj(None, src=2)
        assert obj == "secret"
    pg1.barrier()


def allgather_worker(rank, WORLD_SIZE):
    pg1 = StatelessProcessGroup.create(init_method="tcp://127.0.0.1:29505",
                                       rank=rank,
                                       world_size=WORLD_SIZE)
    data = pg1.all_gather_obj(rank)
    assert data == list(range(WORLD_SIZE))
    pg1.barrier()


112
@multi_gpu_test(num_gpus=4)
113
114
115
@pytest.mark.parametrize(
    "worker", [cpu_worker, gpu_worker, broadcast_worker, allgather_worker])
def test_stateless_process_group(worker):
116
117
118
119
120
121
122
123
124
125
126
127
128
129
    WORLD_SIZE = 4
    from multiprocessing import get_context
    ctx = get_context("fork")
    processes = []
    for i in range(WORLD_SIZE):
        rank = i
        processes.append(ctx.Process(target=worker, args=(rank, WORLD_SIZE)))
    for p in processes:
        p.start()
    for p in processes:
        p.join()
    for p in processes:
        assert not p.exitcode
    print("All processes finished.")