all_to_all_single seems to be missing a check for checkSplitSizes when splitsize=0.
Labels: oncall: distributed

### 🐛 Describe the bug

By reading the source code of alltoall_single, I found that the implementation of alltoall_base is divided into two cases by judging whether the size() of input&output SplitSizes is 0. https://github.com/pytorch/pytorch/blob/v1.9.0/torch/lib/c10d/ProcessGroupNCCL.cpp#L1607

When the size() is not equal to 0, the check of c10d::checkSplitSizes will be performed first.
https://github.com/pytorch/pytorch/blob/v1.9.0/torch/lib/c10d/Utils.hpp#L411
```
inline void checkSplitSizes(
    const std::vector<int64_t>& split_sizes,
    const at::Tensor& tensor,
    int group_size) {
  if (split_sizes.size() == 0) {
    TORCH_CHECK(
        tensor.size(0) % group_size == 0,
        "Tensor's dim 0 does not divide equally across group size");
  } else {
    TORCH_CHECK(
        split_sizes.size() == group_size,
        "Number of tensor splits not equal to group size");
    const auto sum = c10::sum_integers(split_sizes);
    TORCH_CHECK(
        sum == tensor.size(0), "Split sizes doesn't match total dim 0 size");
  }
}
```
 The check shows that split_sizes.size() == 0 will be judged first ,but currently this code seems to never be executed in alltoall_base.
 So this TORCH_CHECK(tensor.size(0) % group_size == 0) does not seem to be executed in a reasonable scenario.
The following tests were performed on the python :
```
import torch
import multiprocessing as mp
import torch.distributed as dist
from torch.nn.parallel import DistributedDataParallel as DDP

INIT_METHOD = 'tcp://127.0.0.5:12345'
TIMEOUT = 100

def spawn_processes(world_size, func):
    processes = []
    # start task
    for rank in range(world_size):
        name = "process " + str(rank)
        process = mp.Process(target=func, name=name, args=(rank, world_size))
        process.start()
        processes.append(process)
    # wait task completion
    for rank, process in enumerate(processes):
        process.join(TIMEOUT)
        if process.is_alive():
            print("Timeout waiting for rank %d to terminate" % rank)
            process.terminate()

def test_alltoall_single_no_split(rank, world_size):
    torch.cuda.set_device(rank)
    dist.init_process_group(backend='nccl', init_method=INIT_METHOD, rank=rank, world_size=world_size)
    input = torch.arange(5, dtype=torch.float).cuda() + rank * 5
    print("input: ", input)
    output = torch.empty([5], dtype=torch.float).cuda()
    dist.all_to_all_single(output, input)
    print("output: ", output)
    dist.destroy_process_group()

if __name__ == "__main__":
    world_size = 4
    spawn_processes(world_size, test_alltoall_single_no_split)
```
In this test case, when (input.size()==5 and world_size==4), the output of result is as follows:
```
input:  tensor([0., 1., 2., 3., 4.], device='cuda:0') 
input:  tensor([5., 6., 7., 8., 9.], device='cuda:1') 
input:  tensor([10., 11., 12., 13., 14.], device='cuda:2') 
input:  tensor([15., 16., 17., 18., 19.], device='cuda:3') 

output:  tensor([ 0.0000e+00, -1.0842e-19,  8.9683e-44,  2.3362e-41, -6.8723e-13],
       device='cuda:0') 
output:  tensor([5.8316e-39, 6.0000e+00, 4.6566e-10, 9.1084e-44, 6.0567e+23],
       device='cuda:1')
output:  tensor([ 2.2959e-41,  5.9578e-39,  1.2000e+01, -3.8519e-34,  6.0447e+23],
       device='cuda:2') 
output:  tensor([-8.9683e-44,  2.3318e-41,  5.9693e-39,  8.0234e+00,  1.4356e+24],
       device='cuda:3')
```
This result doesn't seem like a reasonable situation. So I think whether TORCH_CHECK(tensor.size(0) % group_size == 0) in checkSplitSizes needs to be moved to the case of outputSplitSizes.size() == 0 && inputSplitSizes.size() == 0 of alltoall_base.

### Versions

torch                     1.9.0a0+c3d40fd        
torchvision               0.10.0a0                
numpy                     1.20.3  

cc @mrshenli @pritamdamania87 @zhaojuanmao @satgera @rohan-varma @gqchen @aazzolini @osalpekar @jiayisuse @H-Huang @kwen2501 @awgu