MCPcopy Create free account
hub / github.com/tdrussell/diffusion-pipe / reduce_tensor

Function reduce_tensor

utils/reduction.py:226–403  ·  view source on GitHub ↗
(tensor)

Source from the content-addressed store, hash-verified

224
225
226def reduce_tensor(tensor):
227 if tensor.requires_grad and not tensor.is_leaf:
228 raise RuntimeError(
229 "Cowardly refusing to serialize non-leaf tensor which requires_grad, "
230 "since autograd does not support crossing process boundaries. "
231 "If you just want to transfer the data, call detach() on the tensor "
232 "before serializing (e.g., putting it on the queue)."
233 )
234
235 check_serializing_named_tensor(tensor)
236 torch.utils.hooks.warn_if_has_hooks(tensor)
237
238 # Note [CUDA IPC and the caching allocator]
239 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
240 # When you send a CUDA tensor over IPC, you might expect that you will
241 # get out the same storage from the other end. However, the CUDA caching
242 # allocator makes it difficult to preserve this invariant. Consider
243 # the following situation: a tensor of size 0x100 points to offset 0x20 of
244 # a storage at 0xA100 of size 0x100. (For simplicity, all of these
245 # sizes are given in bytes). HOWEVER, with the caching allocator, this storage
246 # might be part of a larger cudaMalloc allocation 0xA000 of size 0x4000.
247 #
248 # When we want to send this CUDA tensor over IPC, we must send the
249 # *entire* cudaMalloc allocation, i.e., the 0xA000 region, not just
250 # the storage 0xA100 (because that is what CUDA supports). So, on the
251 # other end, there simply isn't any way to say, "Wait, you gave me
252 # a bigger region (0xA000) than the one I wanted (0xA100)".
253 #
254 # OK, so if you sent the cudaMalloc allocation, can you just wrap that up as
255 # one storage itself? No, because this cudaMalloc allocation might contain
256 # storages of mixed types: float, bytes, double... If you make the entire
257 # allocation a single storage of a type A, we'll hit an error when constructing
258 # a tensor of type B on the storage.
259 #
260 # cudaIpcMemHandle is an identifier to access the sender cudaMalloc allocation on the
261 # receiver side. However, cudaIpcMemHandles from each device in a given process may
262 # only be opened by one context per device per other process.
263 # If we open and close a memory handle multiples times in a process, CUDA is allowed
264 # to give it a different address; similarly, once we close the memory, we're not
265 # allowed to access it(and the storage/tensor built on top of it), even if it is
266 # still live in the original process. As we cannot make a cudaMalloc allocation
267 # to a single storage in one go, this requires us to cache the device pointer for
268 # each cudaIpcMemHandle on C++ side to reconstruct types of storages, while keep
269 # the old ones alives.
270 # See [https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__DEVICE.html]
271 #
272 # This is fine, because all we need to do is to save our position in the allocation,
273 # and reconstruct storage and tensor from it.
274 # 0xA000 -> -------CUDA Allocation------
275 # | |
276 # | |
277 # | |
278 # | |
279 # 0xA100 -> --------storage1 begin------
280 # | |
281 # 0xA120 -> --------tensor1 begin ------
282 # | |
283 # | |

Callers 2

reduce_nested_tensorFunction · 0.85
reduce_sparse_tensorFunction · 0.85

Calls 3

reduce_nested_tensorFunction · 0.85
reduce_sparse_tensorFunction · 0.85
StorageWeakRefClass · 0.85

Tested by

no test coverage detected