torch.permute() is carried out just by changing the strides of the dimensions (similar to numpy).
Just to quote from https://ipython-books.github.io/45-understanding-the-internals-of-numpy-to-avoid-unnecessary-array-copying/ 14 :

When reshaping an array, NumPy avoids copies when possible by modifying the  strides  attribute. For example, when transposing a matrix, the order of strides is reversed, but the underlying data remains identical

Here you can look at the code:

  
      github.com
  
  
    pytorch/pytorch/blob/a6170573c898a1367517d8daf8e777abaf96f752/aten/src/ATen/native/TensorShape.cpp#L367-L385 18

Tensor permute(const Tensor& self, IntArrayRef dims) {
auto nDims = self.dim();
AT_CHECK(dims.size() == (size_t)nDims,
         "number of dims don't match in permute");
auto oldSizes = self.sizes();
auto oldStrides = self.strides();
std::vector<int64_t> newSizes(nDims);
std::vector<int64_t> newStrides(nDims);
std::vector<bool> seen(nDims);
for (int64_t i = 0; i < nDims; i++) {
  auto dim = maybe_wrap_dim(dims[i], nDims);
  AT_CHECK(!seen[dim],
           "repeated dim in permute");
  seen[dim] = true;
  newSizes[i] = oldSizes[dim];
  newStrides[i] = oldStrides[dim];
}
return self.as_strided(newSizes, newStrides);
}