Repository: pytorch
Issue: distributed data parallel, gloo backend works, but nccl deadlock
Labels: oncall: distributed,triaged,module: nccl,module: deadlock

I have run into the same problem as #14870 .  Because I cannot reopen the issue, I opened a new issue. But the GPUs are all empty, except that 11MB memory is used (no process running). 

The code is easy to reproduce:
```python
import torch
import sys

dist = '--local_rank' in ''.join(sys.argv)

if dist:
    torch.distributed.init_process_group(backend='nccl')

def get_available_GPUs(N, max_utilization=.5, max_memory_usage=.5):
    '''
    get `N` available GPU ids with *utilization* less than `max_utilization` and *memory usage* less than max_memory_usage
    Arguments:
        N (int): How many GPUs you want to select
        max_utilization (float): GPU with utilization higher than `max_utilization` is considered as not available.
        max_memory_usage (float): GPU with memory usage higher than `max_memory_usage` is considered as not available.

    Returns:
        list containing IDs of available GPUs
    '''
    from subprocess import Popen, PIPE
    cmd = ["nvidia-smi",
           "--query-gpu=index,utilization.gpu,memory.total,memory.used",
           "--format=csv,noheader,nounits"]
    p = Popen(cmd, stdout=PIPE)
    output = p.stdout.read().decode('UTF-8')
    gpus = [[int(x) for x in line.split(',')] for line in output.splitlines()]
    gpu_ids = []
    for (index, utilization, total, used) in gpus:
        if utilization / 100.0 < max_utilization:
            if used * 1.0 / total < max_memory_usage:
                gpu_ids.append(index)
    if len(gpu_ids) < N:
        raise Exception("Only %s GPU(s) available but %s GPU(s) are required!" % (len(gpu_ids), N))
    available = gpu_ids[:N]
    return list(available)

def select_GPUs(N_per_process, max_utilization=.5, max_memory_usage=.5):
    '''
    select `N_per_process` GPUs.
    If distributed training is enabled, GPUs will be assigned properly among different processes.
    Arguments:
        N_per_process (int): How many GPUs you want to select for each process
        max_utilization (float): GPU with utilization higher than `max_utilization` is considered as not available.
        max_memory_usage (float): GPU with memory usage higher than `max_memory_usage` is considered as not available.

    Returns:
        list containing IDs of selected GPUs
    '''
    if not dist:
        return get_available_GPUs(N_per_process, max_utilization, max_memory_usage)
    rank = torch.distributed.get_rank()
    world_size = torch.distributed.get_world_size()
    tensor = torch.zeros(world_size * N_per_process, dtype=torch.int).cuda()
    if rank == 0:
        device_ids = get_available_GPUs(world_size * N_per_process)
        tensor = torch.tensor(device_ids, dtype=torch.int).cuda()
    torch.distributed.broadcast(tensor, 0)
    ids = list(tensor.cpu().numpy().tolist())
    return ids[N_per_process * rank : N_per_process * rank + N_per_process]

import torch.nn as nn
device_ids = select_GPUs(2)
output_device = torch.device(device_ids[0])

x = torch.tensor([5.0, -1.0], dtype=torch.float).cuda(output_device).view(-1, 1)

model = nn.Linear(in_features=1, out_features=1, bias=False).cuda(output_device)

rank = torch.distributed.get_rank()
model.weight.data.zero_()
model.weight.data.add_(rank)

print(f'at rank {rank}, before init, the weight is {model.weight.data.item()}')

model = torch.nn.parallel.DistributedDataParallel(model,device_ids=device_ids, output_device=output_device)

print(f'at rank {rank}, after init, the weight is {model.module.weight.data.item()}')

y = model(x)

label = torch.zeros(2, 1, dtype=torch.float).cuda(output_device)

loss = torch.sum((y - label)**2)

loss.backward()

# print(model.weight.grad)
```

After printing 
```
at rank 0, before init, the weight is 0.0
at rank 1, before init, the weight is 1.0
at rank 0, after init, the weight is 0.0
```
it hangs.

But it works fine with `gloo`.