I don’t think these operation see any significant speedup in C++, if the tensors are “large enough” (i.e. not tiny).
Usually you would just see the Python overhead, which is negligible if you have some workload on the operations.
Both methods should yield a similar timing and I would assume the second approach to be slower.
At least, that’s the result from my profiling:
x = torch.randn(64, 128, 64, 64, device='cuda')
nb_iters = 1000

# warmup
for _ in range(100):
    y = x.permute(0, 3, 2, 1).contiguous()

torch.cuda.synchronize()
t0 = time.time()

for _ in range(nb_iters):
    y = x.permute(0, 3, 2, 1).contiguous()

torch.cuda.synchronize()
t1 = time.time()

print((t1 -t0)/nb_iters)


# warmup
for _ in range(100):
    out =  torch.zeros(64, 64, 64, 128, device='cuda')
    out[:] = x.permute(0, 3, 2, 1)

torch.cuda.synchronize()
t0 = time.time()

for _ in range(nb_iters):
    out =  torch.zeros(64, 64, 64, 128, device='cuda')
    out[:] = x.permute(0, 3, 2, 1)

torch.cuda.synchronize()
t1 = time.time()

print((t1 -t0)/nb_iters)

Permute + contiguous: 0.00072478 s
Permute + copy: 0.00093216 s