auto-sync 2026-07-02T13:37:00Z workspace (part 26)
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +6 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/autograd/rpc_messages/rpc_with_profiling_resp.h +63 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/autograd/rpc_messages/rref_backward_req.h +43 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/autograd/rpc_messages/rref_backward_resp.h +22 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/autograd/utils.h +61 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Backend.hpp +559 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Backoff.hpp +57 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/FakeProcessGroup.hpp +258 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/FileStore.hpp +72 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/FlightRecorder.hpp +336 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/FlightRecorderDetail.hpp +641 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Functional.hpp +182 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/GlooDeviceFactory.hpp +40 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/GroupRegistry.hpp +27 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/HashStore.hpp +86 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/NCCLUtils.hpp +458 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/NanCheck.hpp +17 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ParamCommsUtils.hpp +260 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/PrefixStore.hpp +82 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroup.hpp +1037 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupGloo.hpp +508 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupGlooDetail.hpp +679 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupMPI.hpp +278 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupNCCL.hpp +1547 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupUCC.hpp +363 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupWrapper.hpp +204 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/PyProcessGroup.hpp +361 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/RankLocal.hpp +94 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Store.hpp +172 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/TCPStore.hpp +181 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/TCPStoreBackend.hpp +84 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/TraceUtils.h +324 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Types.hpp +190 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/UCCTracing.hpp +63 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/UCCUtils.hpp +192 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/UnixSockUtils.hpp +30 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Utils.hpp +750 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/WinSockUtils.hpp +30 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Work.hpp +194 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/c10d.h +14 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/comm.hpp +147 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_collectives/ControlCollectives.hpp +64 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_collectives/StoreCollectives.hpp +73 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_plane/Handlers.hpp +82 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_plane/WaitCounterHandler.hpp +20 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_plane/WorkerServer.hpp +37 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/cuda/CUDAEventCache.hpp +34 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/cuda/StreamBlock.hpp +43 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/cuda/utils.hpp +15 -0
- workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/debug.h +28 -0
.gitattributes
CHANGED
|
@@ -226,3 +226,9 @@ workspace/outputs/audit_venv/lib/python3.11/site-packages/pip/_vendor/distlib/t6
|
|
| 226 |
workspace/outputs/audit_venv/lib/python3.11/site-packages/pip/_vendor/distlib/w64-arm.exe filter=lfs diff=lfs merge=lfs -text
|
| 227 |
workspace/outputs/audit_venv/lib/python3.11/site-packages/pip/_vendor/distlib/w64.exe filter=lfs diff=lfs merge=lfs -text
|
| 228 |
workspace/outputs/audit_venv/lib/python3.11/site-packages/pydantic_core/_pydantic_core.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
workspace/outputs/audit_venv/lib/python3.11/site-packages/pip/_vendor/distlib/w64-arm.exe filter=lfs diff=lfs merge=lfs -text
|
| 227 |
workspace/outputs/audit_venv/lib/python3.11/site-packages/pip/_vendor/distlib/w64.exe filter=lfs diff=lfs merge=lfs -text
|
| 228 |
workspace/outputs/audit_venv/lib/python3.11/site-packages/pydantic_core/_pydantic_core.cpython-311-x86_64-linux-gnu.so filter=lfs diff=lfs merge=lfs -text
|
| 229 |
+
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/lib/libc10.so filter=lfs diff=lfs merge=lfs -text
|
| 230 |
+
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/lib/libc10_cuda.so filter=lfs diff=lfs merge=lfs -text
|
| 231 |
+
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/lib/libtorch_cpu.so filter=lfs diff=lfs merge=lfs -text
|
| 232 |
+
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/lib/libtorch_cuda.so filter=lfs diff=lfs merge=lfs -text
|
| 233 |
+
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/lib/libtorch_cuda_linalg.so filter=lfs diff=lfs merge=lfs -text
|
| 234 |
+
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/lib/libtorch_python.so filter=lfs diff=lfs merge=lfs -text
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/autograd/rpc_messages/rpc_with_profiling_resp.h
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <torch/csrc/autograd/profiler.h>
|
| 5 |
+
#include <torch/csrc/distributed/rpc/message.h>
|
| 6 |
+
#include <torch/csrc/distributed/rpc/rpc_agent.h>
|
| 7 |
+
#include <torch/csrc/distributed/rpc/rpc_command_base.h>
|
| 8 |
+
#include <torch/csrc/distributed/rpc/types.h>
|
| 9 |
+
|
| 10 |
+
namespace torch::distributed::autograd {
|
| 11 |
+
class TORCH_API RpcWithProfilingResp : public rpc::RpcCommandBase {
|
| 12 |
+
public:
|
| 13 |
+
// For sending RPCs over the wire
|
| 14 |
+
RpcWithProfilingResp(
|
| 15 |
+
rpc::MessageType messageType,
|
| 16 |
+
c10::intrusive_ptr<rpc::Message> wrappedMessage,
|
| 17 |
+
std::vector<torch::autograd::profiler::LegacyEvent> profiledEvents,
|
| 18 |
+
rpc::ProfilingId profilingId);
|
| 19 |
+
|
| 20 |
+
// For receiving RPCs. Used in from message when converting a message received
|
| 21 |
+
// over the wire.
|
| 22 |
+
RpcWithProfilingResp(
|
| 23 |
+
rpc::MessageType messageType,
|
| 24 |
+
std::unique_ptr<rpc::RpcCommandBase> wrappedRpc,
|
| 25 |
+
rpc::MessageType wrappedMessageType,
|
| 26 |
+
std::vector<torch::Tensor> tensors,
|
| 27 |
+
std::vector<torch::autograd::profiler::LegacyEvent> profiledEvents,
|
| 28 |
+
rpc::ProfilingId profilingId);
|
| 29 |
+
c10::intrusive_ptr<rpc::Message> toMessageImpl() && override;
|
| 30 |
+
static std::unique_ptr<RpcWithProfilingResp> fromMessage(
|
| 31 |
+
const rpc::Message& message);
|
| 32 |
+
// Retrieve remote Events
|
| 33 |
+
std::vector<torch::autograd::profiler::LegacyEvent> getProfiledEvents() const;
|
| 34 |
+
// Retrieve the globally unique profiling ID corresponding to this command.
|
| 35 |
+
const rpc::ProfilingId& getProfilingId() const;
|
| 36 |
+
// Retrieve the original RPC which this ProfilingRPC wraps.
|
| 37 |
+
RpcCommandBase& wrappedRpc();
|
| 38 |
+
// Destructively move the wrapped RPC.
|
| 39 |
+
std::unique_ptr<RpcCommandBase> moveWrappedRpc() &&;
|
| 40 |
+
// Message type of the wrapped RPC
|
| 41 |
+
rpc::MessageType wrappedMessageType() const;
|
| 42 |
+
// Set the wrapped RPC for this RPC.
|
| 43 |
+
void setWrappedRpc(std::unique_ptr<RpcCommandBase> wrappedRpc);
|
| 44 |
+
|
| 45 |
+
private:
|
| 46 |
+
// message type
|
| 47 |
+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
| 48 |
+
const rpc::MessageType messageType_;
|
| 49 |
+
// wrapped message
|
| 50 |
+
c10::intrusive_ptr<rpc::Message> wrappedMessage_;
|
| 51 |
+
std::unique_ptr<RpcCommandBase> wrappedRpc_;
|
| 52 |
+
rpc::MessageType wrappedMessageType_;
|
| 53 |
+
std::vector<torch::Tensor> tensors_;
|
| 54 |
+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
| 55 |
+
const std::vector<torch::autograd::profiler::LegacyEvent> profiledEvents_;
|
| 56 |
+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
| 57 |
+
const rpc::ProfilingId profilingId_;
|
| 58 |
+
};
|
| 59 |
+
} // namespace torch::distributed::autograd
|
| 60 |
+
|
| 61 |
+
#else
|
| 62 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 63 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/autograd/rpc_messages/rref_backward_req.h
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <torch/csrc/distributed/rpc/message.h>
|
| 5 |
+
#include <torch/csrc/distributed/rpc/rpc_command_base.h>
|
| 6 |
+
#include <torch/csrc/distributed/rpc/types.h>
|
| 7 |
+
|
| 8 |
+
namespace torch::distributed::autograd {
|
| 9 |
+
|
| 10 |
+
// Internal system RPC to invoke distributed backward pass on remote nodes when
|
| 11 |
+
// 'rref.backward()' is invoked.
|
| 12 |
+
class TORCH_API RRefBackwardReq : public rpc::RpcCommandBase {
|
| 13 |
+
public:
|
| 14 |
+
RRefBackwardReq(
|
| 15 |
+
const rpc::RRefId& rrefId,
|
| 16 |
+
int64_t autogradContextId,
|
| 17 |
+
bool retainGraph = false);
|
| 18 |
+
|
| 19 |
+
const rpc::RRefId& getRRefId() const;
|
| 20 |
+
|
| 21 |
+
int64_t getAutogradContextId() const;
|
| 22 |
+
|
| 23 |
+
bool retainGraph() const;
|
| 24 |
+
|
| 25 |
+
// Serialization and deserialization methods.
|
| 26 |
+
c10::intrusive_ptr<rpc::Message> toMessageImpl() && override;
|
| 27 |
+
static std::unique_ptr<RRefBackwardReq> fromMessage(
|
| 28 |
+
const rpc::Message& message);
|
| 29 |
+
|
| 30 |
+
private:
|
| 31 |
+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
| 32 |
+
const rpc::RRefId rrefId_;
|
| 33 |
+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
| 34 |
+
const int64_t autogradContextId_;
|
| 35 |
+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
| 36 |
+
const bool retainGraph_;
|
| 37 |
+
};
|
| 38 |
+
|
| 39 |
+
} // namespace torch::distributed::autograd
|
| 40 |
+
|
| 41 |
+
#else
|
| 42 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 43 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/autograd/rpc_messages/rref_backward_resp.h
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <torch/csrc/distributed/rpc/message.h>
|
| 5 |
+
#include <torch/csrc/distributed/rpc/rpc_command_base.h>
|
| 6 |
+
|
| 7 |
+
namespace torch::distributed::autograd {
|
| 8 |
+
|
| 9 |
+
// Response for the RRefBackwardReq.
|
| 10 |
+
class TORCH_API RRefBackwardResp : public rpc::RpcCommandBase {
|
| 11 |
+
public:
|
| 12 |
+
RRefBackwardResp() = default;
|
| 13 |
+
c10::intrusive_ptr<rpc::Message> toMessageImpl() && override;
|
| 14 |
+
static std::unique_ptr<RRefBackwardResp> fromMessage(
|
| 15 |
+
const rpc::Message& message);
|
| 16 |
+
};
|
| 17 |
+
|
| 18 |
+
} // namespace torch::distributed::autograd
|
| 19 |
+
|
| 20 |
+
#else
|
| 21 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 22 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/autograd/utils.h
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <torch/csrc/distributed/autograd/context/context.h>
|
| 5 |
+
#include <torch/csrc/distributed/autograd/rpc_messages/rpc_with_autograd.h>
|
| 6 |
+
#include <torch/csrc/distributed/autograd/rpc_messages/rpc_with_profiling_req.h>
|
| 7 |
+
#include <torch/csrc/distributed/autograd/rpc_messages/rpc_with_profiling_resp.h>
|
| 8 |
+
|
| 9 |
+
namespace torch::distributed::autograd {
|
| 10 |
+
|
| 11 |
+
// This method is used to attach the 'send' autograd function to the autograd
|
| 12 |
+
// graph when we use RPC. This method creates a new 'send' autograd function
|
| 13 |
+
// and attaches the provided tensors as next_edges to the 'send' function. In
|
| 14 |
+
// addition to this, it also registers the send function in the provided
|
| 15 |
+
// autograd context. Finally, the RPC message is updated with appropriate
|
| 16 |
+
// autograd information for the recipient.
|
| 17 |
+
TORCH_API void addSendRpcBackward(
|
| 18 |
+
const ContextPtr& autogradContext,
|
| 19 |
+
const AutogradMetadata& autogradMetadata,
|
| 20 |
+
std::vector<torch::Tensor>& tensors);
|
| 21 |
+
|
| 22 |
+
// This method is used to attach the 'recv' autograd function to the autograd
|
| 23 |
+
// graph when we use RPC. This method creates a new 'recv' autograd function
|
| 24 |
+
// and attaches the provided tensors as inputs to the 'recv' function. It
|
| 25 |
+
// creates a new autograd context if needed and registers the 'recv' function
|
| 26 |
+
// with this context.
|
| 27 |
+
//
|
| 28 |
+
// Returns a pointer to the autograd context created.
|
| 29 |
+
TORCH_API ContextPtr addRecvRpcBackward(
|
| 30 |
+
const AutogradMetadata& autogradMetadata,
|
| 31 |
+
std::vector<torch::Tensor>& tensors,
|
| 32 |
+
rpc::worker_id_t fromWorkerId,
|
| 33 |
+
const rpc::DeviceMap& deviceMap);
|
| 34 |
+
|
| 35 |
+
// This method is a wrapper utility used internally to wrap autograd info
|
| 36 |
+
// and attach autograd function for each type of rpc call if it has valid
|
| 37 |
+
// context and tensors require grads or forceGradRecording is true, in this
|
| 38 |
+
// case, return RpcWithAutograd message; otherwise return original rpc message.
|
| 39 |
+
// NB: forceGradRecording is useful when the request does not contain any tensor
|
| 40 |
+
// but the corresponding response does.
|
| 41 |
+
TORCH_API c10::intrusive_ptr<rpc::Message> getMessageWithAutograd(
|
| 42 |
+
const rpc::worker_id_t dstId,
|
| 43 |
+
c10::intrusive_ptr<rpc::Message> wrappedRpcMsg,
|
| 44 |
+
rpc::MessageType msgType,
|
| 45 |
+
bool forceGradRecording = false,
|
| 46 |
+
const rpc::DeviceMap& deviceMap = {});
|
| 47 |
+
|
| 48 |
+
// Send message after autograd checking
|
| 49 |
+
TORCH_API c10::intrusive_ptr<c10::ivalue::Future> sendMessageWithAutograd(
|
| 50 |
+
rpc::RpcAgent& agent,
|
| 51 |
+
const rpc::WorkerInfo& dst,
|
| 52 |
+
c10::intrusive_ptr<rpc::Message> wrappedRpcMsg,
|
| 53 |
+
bool forceGradRecording = false,
|
| 54 |
+
const float rpcTimeoutSeconds = torch::distributed::rpc::kUnsetRpcTimeout,
|
| 55 |
+
bool forceDisableProfiling = false);
|
| 56 |
+
|
| 57 |
+
} // namespace torch::distributed::autograd
|
| 58 |
+
|
| 59 |
+
#else
|
| 60 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 61 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Backend.hpp
ADDED
|
@@ -0,0 +1,559 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <memory>
|
| 5 |
+
#include <string>
|
| 6 |
+
#include <unordered_map>
|
| 7 |
+
#include <utility>
|
| 8 |
+
#include <vector>
|
| 9 |
+
|
| 10 |
+
#include <ATen/ATen.h>
|
| 11 |
+
#include <c10/core/Allocator.h>
|
| 12 |
+
#include <c10/macros/Macros.h>
|
| 13 |
+
|
| 14 |
+
#include <torch/csrc/distributed/c10d/Types.hpp>
|
| 15 |
+
#include <torch/csrc/distributed/c10d/Utils.hpp>
|
| 16 |
+
#include <torch/csrc/distributed/c10d/Work.hpp>
|
| 17 |
+
#include <torch/csrc/distributed/c10d/debug.h>
|
| 18 |
+
|
| 19 |
+
constexpr auto kBackendDefaultTimeout =
|
| 20 |
+
std::chrono::milliseconds(30 * 60 * 1000);
|
| 21 |
+
|
| 22 |
+
namespace c10d {
|
| 23 |
+
|
| 24 |
+
enum class ErrorType {
|
| 25 |
+
SUCCESS = 0,
|
| 26 |
+
TIMEOUT = 1,
|
| 27 |
+
// e.g., NCCL error, etc
|
| 28 |
+
COMM_ERROR = 2,
|
| 29 |
+
// TODO, do we need to distinguish between remote timeout or remote COMM
|
| 30 |
+
// errors?
|
| 31 |
+
REMOTE_ERROR = 3
|
| 32 |
+
};
|
| 33 |
+
|
| 34 |
+
class TORCH_API Backend : public torch::CustomClassHolder {
|
| 35 |
+
public:
|
| 36 |
+
// Backend Options is a base struct that defines the basic options
|
| 37 |
+
// when constructing a Backend. Each Backend subclass should
|
| 38 |
+
// extend this struct and define its options if it wants to provide more
|
| 39 |
+
// config options (beyond basic ones defined here) to end user.
|
| 40 |
+
struct TORCH_API Options : torch::CustomClassHolder {
|
| 41 |
+
explicit Options(
|
| 42 |
+
std::string backend,
|
| 43 |
+
std::chrono::milliseconds timeout = kBackendDefaultTimeout)
|
| 44 |
+
: timeout(timeout), backend(std::move(backend)) {}
|
| 45 |
+
~Options() override = default;
|
| 46 |
+
Options(const Options&) = default;
|
| 47 |
+
|
| 48 |
+
std::chrono::milliseconds timeout;
|
| 49 |
+
|
| 50 |
+
// backend name
|
| 51 |
+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
| 52 |
+
const std::string backend;
|
| 53 |
+
std::string group_name;
|
| 54 |
+
std::string group_desc;
|
| 55 |
+
std::vector<uint64_t> global_ranks_in_group;
|
| 56 |
+
};
|
| 57 |
+
|
| 58 |
+
explicit Backend(int rank, int size);
|
| 59 |
+
~Backend() override = 0;
|
| 60 |
+
|
| 61 |
+
int getRank() const {
|
| 62 |
+
return rank_;
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
int getSize() const {
|
| 66 |
+
return size_;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
// Returns an unique opaque ID of this backend that can be used to correlate
|
| 70 |
+
// with its collectives.
|
| 71 |
+
int64_t getID() const {
|
| 72 |
+
return reinterpret_cast<std::intptr_t>(this);
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
virtual bool supportsSplitting() const {
|
| 76 |
+
return false;
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
virtual bool supportsCoalescing() const {
|
| 80 |
+
return false;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
virtual bool supportsTimeEstimation() const {
|
| 84 |
+
return false;
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
virtual bool supportsShrinking() const {
|
| 88 |
+
return false;
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
// Shrink the backend by excluding specified ranks. Backends that support
|
| 92 |
+
// communicator shrinking should override this and return a new backend
|
| 93 |
+
// instance representing the shrunken group. Backends may use opts_override
|
| 94 |
+
// to supply backend-specific options for the new group.
|
| 95 |
+
virtual c10::intrusive_ptr<Backend> shrink(
|
| 96 |
+
const std::vector<int64_t>& /*ranks_to_exclude*/,
|
| 97 |
+
int /*shrink_flags*/ = 0,
|
| 98 |
+
const c10::intrusive_ptr<Options>& /*opts_override*/ = nullptr) {
|
| 99 |
+
TORCH_CHECK(
|
| 100 |
+
false,
|
| 101 |
+
c10::str("Backend ", getBackendName(), " does not support shrink"));
|
| 102 |
+
}
|
| 103 |
+
|
| 104 |
+
virtual void setTimeout(std::chrono::milliseconds timeout) {
|
| 105 |
+
TORCH_CHECK(
|
| 106 |
+
false,
|
| 107 |
+
c10::str(
|
| 108 |
+
"Backend ", getBackendName(), " does not support setting timeout"));
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
virtual void startCoalescing() {
|
| 112 |
+
TORCH_CHECK(
|
| 113 |
+
false,
|
| 114 |
+
c10::str(
|
| 115 |
+
"Backend ",
|
| 116 |
+
getBackendName(),
|
| 117 |
+
" does not implement startCoalescing"));
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
virtual c10::intrusive_ptr<Work> endCoalescing() {
|
| 121 |
+
TORCH_CHECK(
|
| 122 |
+
false,
|
| 123 |
+
c10::str(
|
| 124 |
+
"Backend ", getBackendName(), " does not implement endCoalescing"));
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
// Subclasses must override this method to return the backend name
|
| 128 |
+
virtual const std::string getBackendName() const {
|
| 129 |
+
TORCH_INTERNAL_ASSERT(false, "getBackendName is not implemented.");
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
// Subclasses must override this method to return the backend name
|
| 133 |
+
virtual c10::intrusive_ptr<Options> getBackendOptions() {
|
| 134 |
+
TORCH_CHECK(
|
| 135 |
+
false,
|
| 136 |
+
c10::str(
|
| 137 |
+
"Backend ",
|
| 138 |
+
getBackendName(),
|
| 139 |
+
" does not implement getBackendOptions."));
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
virtual c10::intrusive_ptr<Work> broadcast(
|
| 143 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 144 |
+
const BroadcastOptions& /* opts */ = BroadcastOptions()) {
|
| 145 |
+
TORCH_CHECK(
|
| 146 |
+
false,
|
| 147 |
+
c10::str("Backend ", getBackendName(), " does not support broadcast"));
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
virtual c10::intrusive_ptr<Work> allreduce(
|
| 151 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 152 |
+
const AllreduceOptions& /* opts */ = AllreduceOptions()) {
|
| 153 |
+
TORCH_CHECK(
|
| 154 |
+
false,
|
| 155 |
+
c10::str("Backend ", getBackendName(), " does not support allreduce"));
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
virtual c10::intrusive_ptr<Work> allreduce_sparse(
|
| 159 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 160 |
+
const AllreduceOptions& /* opts */ = AllreduceOptions()) {
|
| 161 |
+
TORCH_CHECK(
|
| 162 |
+
false,
|
| 163 |
+
c10::str(
|
| 164 |
+
"Backend ",
|
| 165 |
+
getBackendName(),
|
| 166 |
+
" does not support allreduce sparse"));
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
virtual c10::intrusive_ptr<Work> allreduce_coalesced(
|
| 170 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 171 |
+
const AllreduceCoalescedOptions& /* opts */ =
|
| 172 |
+
AllreduceCoalescedOptions()) {
|
| 173 |
+
TORCH_CHECK(
|
| 174 |
+
false,
|
| 175 |
+
c10::str(
|
| 176 |
+
"Backend ",
|
| 177 |
+
getBackendName(),
|
| 178 |
+
" does not support allreduce_coalesced"));
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
virtual c10::intrusive_ptr<Work> reduce(
|
| 182 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 183 |
+
const ReduceOptions& /* opts */ = ReduceOptions()) {
|
| 184 |
+
TORCH_CHECK(
|
| 185 |
+
false,
|
| 186 |
+
c10::str("Backend ", getBackendName(), " does not support reduce"));
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
virtual c10::intrusive_ptr<Work> allgather(
|
| 190 |
+
std::vector<std::vector<at::Tensor>>& /* outputTensors */,
|
| 191 |
+
std::vector<at::Tensor>& /* inputTensors */,
|
| 192 |
+
const AllgatherOptions& /* opts */ = AllgatherOptions()) {
|
| 193 |
+
TORCH_CHECK(
|
| 194 |
+
false,
|
| 195 |
+
c10::str("Backend ", getBackendName(), " does not support allgather"));
|
| 196 |
+
}
|
| 197 |
+
|
| 198 |
+
// Gathers a single tensor inputBuffer into a single buffer outputBuffer that
|
| 199 |
+
// is interpreted as a contiguous collection of size inputBuffer * WORLD_SIZE.
|
| 200 |
+
// For implementers of ProcessGroup API and advanced users only.
|
| 201 |
+
// Note: this function will be deprecated in near future.
|
| 202 |
+
virtual c10::intrusive_ptr<Work> _allgather_base(
|
| 203 |
+
at::Tensor& /* outputBuffer */,
|
| 204 |
+
at::Tensor& /* inputBuffer */,
|
| 205 |
+
const AllgatherOptions& /* opts */ = AllgatherOptions()) {
|
| 206 |
+
TORCH_CHECK(
|
| 207 |
+
false,
|
| 208 |
+
c10::str(
|
| 209 |
+
"Backend ", getBackendName(), " does not support _allgather_base"));
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
// This function is deprecated and will be moved out of Backend to comms:
|
| 213 |
+
// * do not add dependencies on this function,
|
| 214 |
+
// * do not implement it in your Backend, implement _allgather_base
|
| 215 |
+
// instead.
|
| 216 |
+
virtual c10::intrusive_ptr<Work> allgather_coalesced(
|
| 217 |
+
std::vector<std::vector<at::Tensor>>& /* outputTensorLists */,
|
| 218 |
+
std::vector<at::Tensor>& /* inputTensors */,
|
| 219 |
+
const AllgatherOptions& /* opts */ = AllgatherOptions()) {
|
| 220 |
+
TORCH_CHECK(
|
| 221 |
+
false,
|
| 222 |
+
c10::str(
|
| 223 |
+
"Backend ",
|
| 224 |
+
getBackendName(),
|
| 225 |
+
" does not support allgather_coalesced"));
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
// This function is a coalesced version of `allgather_into_tensor` (currently
|
| 229 |
+
// still named as `_allgather_base`). Each tensor in the vector corresponds to
|
| 230 |
+
// an input/output of one `allgather_into_tensor` operation.
|
| 231 |
+
virtual c10::intrusive_ptr<Work> allgather_into_tensor_coalesced(
|
| 232 |
+
std::vector<at::Tensor>& /* outputs */,
|
| 233 |
+
std::vector<at::Tensor>& /* inputs */,
|
| 234 |
+
const AllgatherOptions& /* opts */ = AllgatherOptions()) {
|
| 235 |
+
TORCH_CHECK(
|
| 236 |
+
false,
|
| 237 |
+
c10::str(
|
| 238 |
+
"Backend ",
|
| 239 |
+
getBackendName(),
|
| 240 |
+
" does not support allgather_into_tensor_coalesced"));
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
virtual c10::intrusive_ptr<Work> gather(
|
| 244 |
+
std::vector<std::vector<at::Tensor>>& /* outputTensors */,
|
| 245 |
+
std::vector<at::Tensor>& /* inputTensors */,
|
| 246 |
+
const GatherOptions& /* opts */ = GatherOptions()) {
|
| 247 |
+
TORCH_CHECK(
|
| 248 |
+
false,
|
| 249 |
+
c10::str("Backend ", getBackendName(), " does not support gather"));
|
| 250 |
+
}
|
| 251 |
+
|
| 252 |
+
virtual c10::intrusive_ptr<Work> scatter(
|
| 253 |
+
std::vector<at::Tensor>& /* outputTensors */,
|
| 254 |
+
std::vector<std::vector<at::Tensor>>& /* inputTensors */,
|
| 255 |
+
const ScatterOptions& /* opts */ = ScatterOptions()) {
|
| 256 |
+
TORCH_CHECK(
|
| 257 |
+
false,
|
| 258 |
+
c10::str("Backend ", getBackendName(), " does not support scatter"));
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
virtual c10::intrusive_ptr<Work> reduce_scatter(
|
| 262 |
+
std::vector<at::Tensor>& /* outputTensors */,
|
| 263 |
+
std::vector<std::vector<at::Tensor>>& /* inputTensors */,
|
| 264 |
+
const ReduceScatterOptions& /* opts */ = ReduceScatterOptions()) {
|
| 265 |
+
TORCH_CHECK(
|
| 266 |
+
false,
|
| 267 |
+
c10::str(
|
| 268 |
+
"Backend ", getBackendName(), " does not support reduce_scatter"));
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
virtual c10::intrusive_ptr<Work> _reduce_scatter_base(
|
| 272 |
+
at::Tensor& /* outputBuffer */,
|
| 273 |
+
at::Tensor& /* inputBuffer */,
|
| 274 |
+
const ReduceScatterOptions& /* opts */ = ReduceScatterOptions()) {
|
| 275 |
+
TORCH_CHECK(
|
| 276 |
+
false,
|
| 277 |
+
c10::str(
|
| 278 |
+
"Backend ",
|
| 279 |
+
getBackendName(),
|
| 280 |
+
" does not support _reduce_scatter_base"));
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
// This function is a coalesced version of `reduce_scatter_tensor` (currently
|
| 284 |
+
// still named as `_reduce_scatter_base`). Each tensor in the vector
|
| 285 |
+
// corresponds to an input/output of one `reduce_scatter_tensor` operation.
|
| 286 |
+
virtual c10::intrusive_ptr<Work> reduce_scatter_tensor_coalesced(
|
| 287 |
+
std::vector<at::Tensor>& /* outputs */,
|
| 288 |
+
std::vector<at::Tensor>& /* inputs */,
|
| 289 |
+
const ReduceScatterOptions& /* opts */ = ReduceScatterOptions()) {
|
| 290 |
+
TORCH_CHECK(
|
| 291 |
+
false,
|
| 292 |
+
c10::str(
|
| 293 |
+
"Backend ",
|
| 294 |
+
getBackendName(),
|
| 295 |
+
" does not support reduce_scatter_tensor_coalesced"));
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
virtual c10::intrusive_ptr<Work> alltoall_base(
|
| 299 |
+
at::Tensor& /* outputBuffer */,
|
| 300 |
+
at::Tensor& /* inputBuffer */,
|
| 301 |
+
std::vector<int64_t>& /* outputSplitSizes */,
|
| 302 |
+
std::vector<int64_t>& /* inputSplitSizes */,
|
| 303 |
+
const AllToAllOptions& /* opts */ = AllToAllOptions()) {
|
| 304 |
+
TORCH_CHECK(
|
| 305 |
+
false,
|
| 306 |
+
c10::str(
|
| 307 |
+
"Backend ", getBackendName(), " does not support alltoall_base"));
|
| 308 |
+
}
|
| 309 |
+
|
| 310 |
+
virtual c10::intrusive_ptr<Work> alltoall(
|
| 311 |
+
std::vector<at::Tensor>& /* outputTensors */,
|
| 312 |
+
std::vector<at::Tensor>& /* inputTensors */,
|
| 313 |
+
const AllToAllOptions& opts = AllToAllOptions()) {
|
| 314 |
+
TORCH_CHECK(
|
| 315 |
+
false,
|
| 316 |
+
c10::str("Backend ", getBackendName(), " does not support alltoall"));
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
virtual void monitoredBarrier(
|
| 320 |
+
const BarrierOptions& /* unused */,
|
| 321 |
+
bool /* unused */ = false) {
|
| 322 |
+
auto backendName = getBackendName();
|
| 323 |
+
TORCH_CHECK(
|
| 324 |
+
false,
|
| 325 |
+
c10::str(
|
| 326 |
+
"Backend ",
|
| 327 |
+
backendName,
|
| 328 |
+
" does not support monitoredBarrier, only GLOO supports monitored barrier."));
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
// Agrees on an initial sequence number for the whole group by having rank 0
|
| 332 |
+
// create it and broadcast it to other ranks using the store. Only implemented
|
| 333 |
+
// for GLOO and NCCL backends currently.
|
| 334 |
+
virtual void setSequenceNumberForGroup() {
|
| 335 |
+
auto backendName = getBackendName();
|
| 336 |
+
TORCH_CHECK(
|
| 337 |
+
false,
|
| 338 |
+
c10::str(
|
| 339 |
+
"Backend ",
|
| 340 |
+
backendName,
|
| 341 |
+
" does not yet support sequence numbers."));
|
| 342 |
+
}
|
| 343 |
+
|
| 344 |
+
// Retrieves the current sequence number for the whole group, which should be
|
| 345 |
+
// in sync. If the returned number is not consistent across the group, it
|
| 346 |
+
// may indicate that there is some sort of collective desynchronization.
|
| 347 |
+
virtual uint64_t getSequenceNumberForGroup() {
|
| 348 |
+
auto backendName = getBackendName();
|
| 349 |
+
TORCH_CHECK(
|
| 350 |
+
false,
|
| 351 |
+
c10::str(
|
| 352 |
+
"Backend ",
|
| 353 |
+
backendName,
|
| 354 |
+
" does not yet support sequence numbers."));
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
virtual c10::intrusive_ptr<Work> send(
|
| 358 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 359 |
+
int /* dstRank */,
|
| 360 |
+
int /* tag */) {
|
| 361 |
+
TORCH_CHECK(
|
| 362 |
+
false,
|
| 363 |
+
c10::str("Backend ", getBackendName(), " does not support send"));
|
| 364 |
+
}
|
| 365 |
+
|
| 366 |
+
virtual c10::intrusive_ptr<Work> recv(
|
| 367 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 368 |
+
int /* srcRank */,
|
| 369 |
+
int /* tag */) {
|
| 370 |
+
TORCH_CHECK(
|
| 371 |
+
false,
|
| 372 |
+
c10::str("Backend ", getBackendName(), " does not support recv"));
|
| 373 |
+
}
|
| 374 |
+
|
| 375 |
+
virtual c10::intrusive_ptr<Work> recvAnysource(
|
| 376 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 377 |
+
int /* tag */) {
|
| 378 |
+
TORCH_CHECK(
|
| 379 |
+
false,
|
| 380 |
+
c10::str(
|
| 381 |
+
"Backend ", getBackendName(), " does not support recvAnysource"));
|
| 382 |
+
}
|
| 383 |
+
|
| 384 |
+
virtual c10::intrusive_ptr<Work> barrier(
|
| 385 |
+
const BarrierOptions& /* opts */ = BarrierOptions()) {
|
| 386 |
+
TORCH_CHECK(
|
| 387 |
+
false,
|
| 388 |
+
c10::str("Backend ", getBackendName(), " does not support barrier"));
|
| 389 |
+
}
|
| 390 |
+
|
| 391 |
+
virtual void registerOnCompletionHook(
|
| 392 |
+
std::function<void(std::shared_ptr<WorkInfo>)>&& hook) {
|
| 393 |
+
TORCH_CHECK(
|
| 394 |
+
false,
|
| 395 |
+
"Only ProcessGrouppNCCL supports onCompletion hook, but got ",
|
| 396 |
+
getBackendName(),
|
| 397 |
+
" backend.");
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
virtual void waitForPendingWorks() {
|
| 401 |
+
TORCH_CHECK(
|
| 402 |
+
false,
|
| 403 |
+
"Only ProcessGrouppNCCL supports waitForPendingWorks, but got ",
|
| 404 |
+
getBackendName(),
|
| 405 |
+
" backend.");
|
| 406 |
+
}
|
| 407 |
+
|
| 408 |
+
virtual void enableCollectivesTiming() {
|
| 409 |
+
TORCH_CHECK(
|
| 410 |
+
false,
|
| 411 |
+
"Backend ",
|
| 412 |
+
getBackendName(),
|
| 413 |
+
" is missing implementation of enableCollectivesTiming.");
|
| 414 |
+
}
|
| 415 |
+
|
| 416 |
+
virtual c10::intrusive_ptr<Backend> split(
|
| 417 |
+
const c10::intrusive_ptr<Store>& store,
|
| 418 |
+
const std::vector<int>& ranks,
|
| 419 |
+
const c10::intrusive_ptr<Options>& opts) {
|
| 420 |
+
TORCH_CHECK(
|
| 421 |
+
false,
|
| 422 |
+
"Backend ",
|
| 423 |
+
getBackendName(),
|
| 424 |
+
" is missing implementation of split.");
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
virtual c10::intrusive_ptr<Backend> merge(
|
| 428 |
+
const c10::intrusive_ptr<Store>& store,
|
| 429 |
+
const c10::intrusive_ptr<Options>& opts,
|
| 430 |
+
const int& rank,
|
| 431 |
+
const int& size) {
|
| 432 |
+
TORCH_CHECK(
|
| 433 |
+
false,
|
| 434 |
+
"Backend ",
|
| 435 |
+
getBackendName(),
|
| 436 |
+
" is missing implementation of merge.");
|
| 437 |
+
}
|
| 438 |
+
|
| 439 |
+
bool hasHooks() const {
|
| 440 |
+
return onCompletionHook_ != nullptr;
|
| 441 |
+
}
|
| 442 |
+
|
| 443 |
+
// Do not call this directly, use ProcessGroup::setGroupName instead.
|
| 444 |
+
virtual void setGroupUid(const std::string& pg_uid) {
|
| 445 |
+
pg_uid_ = pg_uid;
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
const std::string& getGroupUid() const {
|
| 449 |
+
return pg_uid_;
|
| 450 |
+
}
|
| 451 |
+
|
| 452 |
+
void setGroupDesc(const std::string& desc) {
|
| 453 |
+
pg_desc_ = desc;
|
| 454 |
+
}
|
| 455 |
+
|
| 456 |
+
const std::string& getGroupDesc() const {
|
| 457 |
+
return pg_desc_;
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
// See similar functions in ProcessGroup.hpp for context.
|
| 461 |
+
std::optional<at::Device> getBoundDeviceId() const {
|
| 462 |
+
return bound_device_id_;
|
| 463 |
+
}
|
| 464 |
+
|
| 465 |
+
// Perform an eager connect to the specified device if the backend supports
|
| 466 |
+
// it.
|
| 467 |
+
virtual void eagerConnectSingleDevice(at::Device device) {
|
| 468 |
+
// no-op in the default case; this is an optimization some
|
| 469 |
+
// backends may perform
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
void setBoundDeviceId(std::optional<at::Device> device) {
|
| 473 |
+
if (device) {
|
| 474 |
+
TORCH_CHECK(device->has_index(), "setBoundDeviceId must have an index");
|
| 475 |
+
}
|
| 476 |
+
bound_device_id_ = device;
|
| 477 |
+
}
|
| 478 |
+
|
| 479 |
+
virtual ErrorType getError() {
|
| 480 |
+
TORCH_CHECK(
|
| 481 |
+
false,
|
| 482 |
+
c10::str("Backend ", getBackendName(), " does not support getError"));
|
| 483 |
+
}
|
| 484 |
+
|
| 485 |
+
virtual std::shared_ptr<c10::Allocator> getMemAllocator() {
|
| 486 |
+
TORCH_CHECK(
|
| 487 |
+
false,
|
| 488 |
+
c10::str(
|
| 489 |
+
"Backend ", getBackendName(), " does not support getMemAllocator"));
|
| 490 |
+
}
|
| 491 |
+
|
| 492 |
+
// Allocate tensor (aten::empty) from backend's communication-optimized memory
|
| 493 |
+
// pool
|
| 494 |
+
virtual at::Tensor allocateTensor(long size, at::TensorOptions options = {}) {
|
| 495 |
+
TORCH_CHECK(
|
| 496 |
+
false,
|
| 497 |
+
c10::str(
|
| 498 |
+
"Backend ", getBackendName(), " does not support allocateTensor"));
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
+
// Returns true if backend supports tensor allocation
|
| 502 |
+
virtual bool supportsTensorAlloc(c10::DeviceIndex deviceIdx) {
|
| 503 |
+
// Change to true in concrete backend if supported
|
| 504 |
+
return false;
|
| 505 |
+
}
|
| 506 |
+
|
| 507 |
+
// Aborts all pending operations and connections in the backend if the backend
|
| 508 |
+
// supports it.
|
| 509 |
+
virtual void abort() {}
|
| 510 |
+
|
| 511 |
+
// Shutdown the backend if the backend supports it. This should be used for
|
| 512 |
+
// normal shutdown.
|
| 513 |
+
virtual void shutdown() {}
|
| 514 |
+
|
| 515 |
+
// APIs related to memory offload
|
| 516 |
+
virtual void suspend() {
|
| 517 |
+
TORCH_CHECK(
|
| 518 |
+
false,
|
| 519 |
+
c10::str("Backend ", getBackendName(), " does not support suspend"));
|
| 520 |
+
}
|
| 521 |
+
|
| 522 |
+
virtual void resume() {
|
| 523 |
+
TORCH_CHECK(
|
| 524 |
+
false,
|
| 525 |
+
c10::str("Backend ", getBackendName(), " does not support resume"));
|
| 526 |
+
}
|
| 527 |
+
|
| 528 |
+
virtual std::unordered_map<std::string, uint64_t> getMemoryStats() {
|
| 529 |
+
TORCH_CHECK(
|
| 530 |
+
false,
|
| 531 |
+
c10::str(
|
| 532 |
+
"Backend ", getBackendName(), " does not support getMemoryStats"));
|
| 533 |
+
}
|
| 534 |
+
|
| 535 |
+
protected:
|
| 536 |
+
// Implementations of this interface need to call this to setup
|
| 537 |
+
// appropriate logging etc.
|
| 538 |
+
void init();
|
| 539 |
+
|
| 540 |
+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
| 541 |
+
const int rank_;
|
| 542 |
+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
| 543 |
+
const int size_;
|
| 544 |
+
// Debug level setting. It is parsed once when ProcessGroup is constructed and
|
| 545 |
+
// remains the same across use of this process group.
|
| 546 |
+
DebugLevel dist_debug_level_;
|
| 547 |
+
std::string pg_uid_;
|
| 548 |
+
std::string pg_desc_;
|
| 549 |
+
|
| 550 |
+
std::function<void(std::shared_ptr<WorkInfo>)> onCompletionHook_;
|
| 551 |
+
|
| 552 |
+
std::optional<at::Device> bound_device_id_;
|
| 553 |
+
};
|
| 554 |
+
|
| 555 |
+
} // namespace c10d
|
| 556 |
+
|
| 557 |
+
#else
|
| 558 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 559 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Backoff.hpp
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <chrono>
|
| 5 |
+
#include <random>
|
| 6 |
+
#include <thread>
|
| 7 |
+
|
| 8 |
+
#include <c10/macros/Macros.h>
|
| 9 |
+
|
| 10 |
+
namespace c10d {
|
| 11 |
+
|
| 12 |
+
class TORCH_API Backoff {
|
| 13 |
+
public:
|
| 14 |
+
virtual ~Backoff() = default;
|
| 15 |
+
|
| 16 |
+
virtual std::chrono::milliseconds nextBackoff() = 0;
|
| 17 |
+
virtual void reset() = 0;
|
| 18 |
+
|
| 19 |
+
void sleepBackoff() {
|
| 20 |
+
std::this_thread::sleep_for(nextBackoff());
|
| 21 |
+
}
|
| 22 |
+
};
|
| 23 |
+
|
| 24 |
+
class TORCH_API ExponentialBackoffWithJitter : public Backoff {
|
| 25 |
+
public:
|
| 26 |
+
ExponentialBackoffWithJitter();
|
| 27 |
+
|
| 28 |
+
std::chrono::milliseconds nextBackoff() override;
|
| 29 |
+
void reset() override;
|
| 30 |
+
|
| 31 |
+
public:
|
| 32 |
+
std::chrono::milliseconds initialInterval{500};
|
| 33 |
+
double randomizationFactor{0.5};
|
| 34 |
+
double multiplier{1.5};
|
| 35 |
+
std::chrono::milliseconds maxInterval{60000};
|
| 36 |
+
|
| 37 |
+
private:
|
| 38 |
+
std::mt19937 gen_;
|
| 39 |
+
std::chrono::milliseconds currentInterval_{0};
|
| 40 |
+
};
|
| 41 |
+
|
| 42 |
+
class TORCH_API FixedBackoff : public Backoff {
|
| 43 |
+
public:
|
| 44 |
+
FixedBackoff(std::chrono::milliseconds interval);
|
| 45 |
+
|
| 46 |
+
std::chrono::milliseconds nextBackoff() override;
|
| 47 |
+
void reset() override;
|
| 48 |
+
|
| 49 |
+
private:
|
| 50 |
+
std::chrono::milliseconds interval_;
|
| 51 |
+
};
|
| 52 |
+
|
| 53 |
+
} // namespace c10d
|
| 54 |
+
|
| 55 |
+
#else
|
| 56 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 57 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/FakeProcessGroup.hpp
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <torch/csrc/distributed/c10d/Backend.hpp>
|
| 5 |
+
#include <torch/csrc/utils.h>
|
| 6 |
+
|
| 7 |
+
namespace c10d {
|
| 8 |
+
|
| 9 |
+
class FakeWork : public Work {
|
| 10 |
+
public:
|
| 11 |
+
int seq_id = -1;
|
| 12 |
+
bool wait(std::chrono::milliseconds timeout = kNoTimeout) override {
|
| 13 |
+
return true;
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
c10::intrusive_ptr<c10::ivalue::Future> getFuture() override {
|
| 17 |
+
auto fut = c10::make_intrusive<c10::ivalue::Future>(c10::NoneType::get());
|
| 18 |
+
fut->markCompleted();
|
| 19 |
+
return fut;
|
| 20 |
+
}
|
| 21 |
+
};
|
| 22 |
+
|
| 23 |
+
class FakeProcessGroup : public Backend {
|
| 24 |
+
public:
|
| 25 |
+
struct Options : Backend::Options {
|
| 26 |
+
explicit Options() : Backend::Options("fake") {}
|
| 27 |
+
|
| 28 |
+
int fake_option = 0;
|
| 29 |
+
bool error_on_collective = false;
|
| 30 |
+
};
|
| 31 |
+
|
| 32 |
+
// Static factory method for official APIs
|
| 33 |
+
static c10::intrusive_ptr<FakeProcessGroup> _create_internal(
|
| 34 |
+
int rank,
|
| 35 |
+
int size,
|
| 36 |
+
c10::intrusive_ptr<Options> options = c10::make_intrusive<Options>()) {
|
| 37 |
+
return c10::make_intrusive<FakeProcessGroup>(
|
| 38 |
+
rank, size, std::move(options));
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
const std::string getBackendName() const override {
|
| 42 |
+
return "fake";
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
c10::intrusive_ptr<Backend::Options> getBackendOptions() override {
|
| 46 |
+
return c10::static_intrusive_pointer_cast<Backend::Options>(options_);
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
c10::intrusive_ptr<Work> broadcast(
|
| 50 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 51 |
+
const BroadcastOptions& /* opts */ = BroadcastOptions()) override {
|
| 52 |
+
checkCollectiveError();
|
| 53 |
+
return c10::make_intrusive<FakeWork>();
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
c10::intrusive_ptr<Work> allreduce(
|
| 57 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 58 |
+
const AllreduceOptions& /* opts */ = AllreduceOptions()) override {
|
| 59 |
+
checkCollectiveError();
|
| 60 |
+
return c10::make_intrusive<FakeWork>();
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
c10::intrusive_ptr<Work> allreduce_sparse(
|
| 64 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 65 |
+
const AllreduceOptions& /* opts */ = AllreduceOptions()) override {
|
| 66 |
+
checkCollectiveError();
|
| 67 |
+
return c10::make_intrusive<FakeWork>();
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
c10::intrusive_ptr<Work> allreduce_coalesced(
|
| 71 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 72 |
+
const AllreduceCoalescedOptions& /* opts */ =
|
| 73 |
+
AllreduceCoalescedOptions()) override {
|
| 74 |
+
checkCollectiveError();
|
| 75 |
+
return c10::make_intrusive<FakeWork>();
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
c10::intrusive_ptr<Work> reduce(
|
| 79 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 80 |
+
const ReduceOptions& /* opts */ = ReduceOptions()) override {
|
| 81 |
+
checkCollectiveError();
|
| 82 |
+
return c10::make_intrusive<FakeWork>();
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
// NOTE [allgather on FakeProcessGroup]
|
| 86 |
+
// Assume each rank have the same input tensor so we just copy to the results
|
| 87 |
+
// since it's not a real allgather, we simply make this copying logic to let
|
| 88 |
+
// some simple validation works (i.e. calling allgather to see if each rank
|
| 89 |
+
// have the same tensor or not).
|
| 90 |
+
//
|
| 91 |
+
// NOTE: in general it's not good form to try to make FakeProcessGroup work
|
| 92 |
+
// with real data, but the reasoning here is that we want FakeProcessGroup to
|
| 93 |
+
// work with DeviceMesh's init code that have the data validation, which
|
| 94 |
+
// makes it worth the tradeoff.
|
| 95 |
+
c10::intrusive_ptr<Work> allgather(
|
| 96 |
+
std::vector<std::vector<at::Tensor>>& outputTensors,
|
| 97 |
+
std::vector<at::Tensor>& inputTensors,
|
| 98 |
+
const AllgatherOptions& /* opts */ = AllgatherOptions()) override {
|
| 99 |
+
checkCollectiveError();
|
| 100 |
+
for (auto& tensor : outputTensors[0]) {
|
| 101 |
+
tensor.copy_(inputTensors[0]);
|
| 102 |
+
}
|
| 103 |
+
return c10::make_intrusive<FakeWork>();
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
c10::intrusive_ptr<Work> _allgather_base(
|
| 107 |
+
at::Tensor& outputBuffer,
|
| 108 |
+
at::Tensor& inputBuffer,
|
| 109 |
+
const AllgatherOptions& /* opts */ = AllgatherOptions()) override {
|
| 110 |
+
checkCollectiveError();
|
| 111 |
+
auto chunks = outputBuffer.chunk(size_);
|
| 112 |
+
for (auto& tensor : chunks) {
|
| 113 |
+
tensor.copy_(inputBuffer);
|
| 114 |
+
}
|
| 115 |
+
return c10::make_intrusive<FakeWork>();
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
c10::intrusive_ptr<Work> allgather_coalesced(
|
| 119 |
+
std::vector<std::vector<at::Tensor>>& /* outputTensorLists */,
|
| 120 |
+
std::vector<at::Tensor>& /* inputTensors */,
|
| 121 |
+
const AllgatherOptions& /* opts */ = AllgatherOptions()) override {
|
| 122 |
+
checkCollectiveError();
|
| 123 |
+
return c10::make_intrusive<FakeWork>();
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
c10::intrusive_ptr<Work> allgather_into_tensor_coalesced(
|
| 127 |
+
std::vector<at::Tensor>& outputs,
|
| 128 |
+
std::vector<at::Tensor>& inputs,
|
| 129 |
+
const AllgatherOptions& /* opts */ = AllgatherOptions()) override {
|
| 130 |
+
checkCollectiveError();
|
| 131 |
+
for (size_t i = 0; i < outputs.size(); ++i) {
|
| 132 |
+
auto chunks = outputs[i].chunk(size_);
|
| 133 |
+
for (auto& chunk : chunks) {
|
| 134 |
+
chunk.copy_(inputs[i]);
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
return c10::make_intrusive<FakeWork>();
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
c10::intrusive_ptr<Work> gather(
|
| 141 |
+
std::vector<std::vector<at::Tensor>>& /* outputTensors */,
|
| 142 |
+
std::vector<at::Tensor>& /* inputTensors */,
|
| 143 |
+
const GatherOptions& /* opts */ = GatherOptions()) override {
|
| 144 |
+
checkCollectiveError();
|
| 145 |
+
return c10::make_intrusive<FakeWork>();
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
c10::intrusive_ptr<Work> scatter(
|
| 149 |
+
std::vector<at::Tensor>& /* outputTensors */,
|
| 150 |
+
std::vector<std::vector<at::Tensor>>& /* inputTensors */,
|
| 151 |
+
const ScatterOptions& /* opts */ = ScatterOptions()) override {
|
| 152 |
+
checkCollectiveError();
|
| 153 |
+
return c10::make_intrusive<FakeWork>();
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
c10::intrusive_ptr<Work> reduce_scatter(
|
| 157 |
+
std::vector<at::Tensor>& /* outputTensors */,
|
| 158 |
+
std::vector<std::vector<at::Tensor>>& /* inputTensors */,
|
| 159 |
+
const ReduceScatterOptions& /* opts */ =
|
| 160 |
+
ReduceScatterOptions()) override {
|
| 161 |
+
checkCollectiveError();
|
| 162 |
+
return c10::make_intrusive<FakeWork>();
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
c10::intrusive_ptr<Work> _reduce_scatter_base(
|
| 166 |
+
at::Tensor& /* outputBuffer */,
|
| 167 |
+
at::Tensor& /* inputBuffer */,
|
| 168 |
+
const ReduceScatterOptions& /* opts */ =
|
| 169 |
+
ReduceScatterOptions()) override {
|
| 170 |
+
checkCollectiveError();
|
| 171 |
+
return c10::make_intrusive<FakeWork>();
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
c10::intrusive_ptr<Work> reduce_scatter_tensor_coalesced(
|
| 175 |
+
std::vector<at::Tensor>& /* outputs */,
|
| 176 |
+
std::vector<at::Tensor>& /* inputs */,
|
| 177 |
+
const ReduceScatterOptions& /* opts */ =
|
| 178 |
+
ReduceScatterOptions()) override {
|
| 179 |
+
checkCollectiveError();
|
| 180 |
+
return c10::make_intrusive<FakeWork>();
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
c10::intrusive_ptr<Work> alltoall_base(
|
| 184 |
+
at::Tensor& /* outputBuffer */,
|
| 185 |
+
at::Tensor& /* inputBuffer */,
|
| 186 |
+
std::vector<int64_t>& /* outputSplitSizes */,
|
| 187 |
+
std::vector<int64_t>& /* inputSplitSizes */,
|
| 188 |
+
const AllToAllOptions& /* opts */ = AllToAllOptions()) override {
|
| 189 |
+
checkCollectiveError();
|
| 190 |
+
return c10::make_intrusive<FakeWork>();
|
| 191 |
+
}
|
| 192 |
+
|
| 193 |
+
c10::intrusive_ptr<Work> alltoall(
|
| 194 |
+
std::vector<at::Tensor>& /* outputTensors */,
|
| 195 |
+
std::vector<at::Tensor>& /* inputTensors */,
|
| 196 |
+
const AllToAllOptions& opts = AllToAllOptions()) override {
|
| 197 |
+
checkCollectiveError();
|
| 198 |
+
return c10::make_intrusive<FakeWork>();
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
c10::intrusive_ptr<Work> send(
|
| 202 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 203 |
+
int /* dstRank */,
|
| 204 |
+
int /* tag */) override {
|
| 205 |
+
return c10::make_intrusive<FakeWork>();
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
c10::intrusive_ptr<Work> recv(
|
| 209 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 210 |
+
int /* srcRank */,
|
| 211 |
+
int /* tag */) override {
|
| 212 |
+
return c10::make_intrusive<FakeWork>();
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
c10::intrusive_ptr<Work> recvAnysource(
|
| 216 |
+
std::vector<at::Tensor>& /* tensors */,
|
| 217 |
+
int /* tag */) override {
|
| 218 |
+
return c10::make_intrusive<FakeWork>();
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
void startCoalescing() override {
|
| 222 |
+
// No-op
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
c10::intrusive_ptr<Work> endCoalescing(OpType /* optype */) {
|
| 226 |
+
checkCollectiveError();
|
| 227 |
+
return c10::make_intrusive<FakeWork>();
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
c10::intrusive_ptr<Work> endCoalescing() override {
|
| 231 |
+
checkCollectiveError();
|
| 232 |
+
return c10::make_intrusive<FakeWork>();
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
c10::intrusive_ptr<Work> barrier(
|
| 236 |
+
const BarrierOptions& /* opts */ = BarrierOptions()) override {
|
| 237 |
+
checkCollectiveError();
|
| 238 |
+
return c10::make_intrusive<FakeWork>();
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
// Private constructor used by official APIs
|
| 242 |
+
FakeProcessGroup(int rank, int size, c10::intrusive_ptr<Options> options)
|
| 243 |
+
: Backend(rank, size), options_(std::move(options)) {}
|
| 244 |
+
c10::intrusive_ptr<Options> options_;
|
| 245 |
+
|
| 246 |
+
private:
|
| 247 |
+
void checkCollectiveError() {
|
| 248 |
+
TORCH_CHECK(
|
| 249 |
+
!options_ || !options_->error_on_collective,
|
| 250 |
+
"FakeProcessGroup collective operation error (error_on_collective=true)");
|
| 251 |
+
}
|
| 252 |
+
};
|
| 253 |
+
|
| 254 |
+
} // namespace c10d
|
| 255 |
+
|
| 256 |
+
#else
|
| 257 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 258 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/FileStore.hpp
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <sys/types.h>
|
| 5 |
+
|
| 6 |
+
#include <mutex>
|
| 7 |
+
#include <unordered_map>
|
| 8 |
+
|
| 9 |
+
#include <torch/csrc/distributed/c10d/Store.hpp>
|
| 10 |
+
|
| 11 |
+
namespace c10d {
|
| 12 |
+
|
| 13 |
+
class TORCH_API FileStore : public Store {
|
| 14 |
+
public:
|
| 15 |
+
explicit FileStore(std::string path, int numWorkers);
|
| 16 |
+
|
| 17 |
+
c10::intrusive_ptr<Store> clone() override;
|
| 18 |
+
|
| 19 |
+
~FileStore() override;
|
| 20 |
+
|
| 21 |
+
void set(const std::string& key, const std::vector<uint8_t>& value) override;
|
| 22 |
+
|
| 23 |
+
std::vector<uint8_t> compareSet(
|
| 24 |
+
const std::string& key,
|
| 25 |
+
const std::vector<uint8_t>& expectedValue,
|
| 26 |
+
const std::vector<uint8_t>& desiredValue) override;
|
| 27 |
+
|
| 28 |
+
std::vector<uint8_t> get(const std::string& key) override;
|
| 29 |
+
|
| 30 |
+
int64_t add(const std::string& key, int64_t value) override;
|
| 31 |
+
|
| 32 |
+
int64_t getNumKeys() override;
|
| 33 |
+
|
| 34 |
+
bool deleteKey(const std::string& key) override;
|
| 35 |
+
|
| 36 |
+
bool check(const std::vector<std::string>& keys) override;
|
| 37 |
+
|
| 38 |
+
void wait(const std::vector<std::string>& keys) override;
|
| 39 |
+
|
| 40 |
+
void wait(
|
| 41 |
+
const std::vector<std::string>& keys,
|
| 42 |
+
const std::chrono::milliseconds& timeout) override;
|
| 43 |
+
|
| 44 |
+
// Returns the path used by the FileStore.
|
| 45 |
+
const std::string& getPath() const noexcept {
|
| 46 |
+
return path_;
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
std::vector<std::string> listKeys() override;
|
| 50 |
+
|
| 51 |
+
protected:
|
| 52 |
+
int64_t addHelper(const std::string& key, int64_t i);
|
| 53 |
+
|
| 54 |
+
std::string path_;
|
| 55 |
+
off_t pos_{0};
|
| 56 |
+
|
| 57 |
+
int numWorkers_;
|
| 58 |
+
const std::string cleanupKey_;
|
| 59 |
+
const std::string refCountKey_;
|
| 60 |
+
const std::string regularPrefix_;
|
| 61 |
+
const std::string deletePrefix_;
|
| 62 |
+
|
| 63 |
+
std::unordered_map<std::string, std::vector<uint8_t>> cache_;
|
| 64 |
+
|
| 65 |
+
std::mutex activeFileOpLock_;
|
| 66 |
+
};
|
| 67 |
+
|
| 68 |
+
} // namespace c10d
|
| 69 |
+
|
| 70 |
+
#else
|
| 71 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 72 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/FlightRecorder.hpp
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
#include <cstdio>
|
| 4 |
+
#include <cstdlib>
|
| 5 |
+
|
| 6 |
+
#include <memory>
|
| 7 |
+
#include <mutex>
|
| 8 |
+
|
| 9 |
+
#include <ATen/ATen.h>
|
| 10 |
+
#include <c10/util/Exception.h>
|
| 11 |
+
#include <torch/csrc/distributed/c10d/TraceUtils.h>
|
| 12 |
+
#include <torch/csrc/distributed/c10d/logger.hpp>
|
| 13 |
+
#include <optional>
|
| 14 |
+
|
| 15 |
+
namespace c10d {
|
| 16 |
+
|
| 17 |
+
#define DEFINE_CONSTANT(name, value) \
|
| 18 |
+
static c10::IValue name = value; \
|
| 19 |
+
static std::string name##_str = value;
|
| 20 |
+
// Update whenever changing contents or formatting of the dump
|
| 21 |
+
// (minor when adding fields, major when changing existing fields)
|
| 22 |
+
// Also update both JSON and Pickle dumps to make use of the newly defined
|
| 23 |
+
// field(s).
|
| 24 |
+
DEFINE_CONSTANT(version_val, "2.10")
|
| 25 |
+
DEFINE_CONSTANT(entries_key, "entries")
|
| 26 |
+
DEFINE_CONSTANT(nccl_comm_key, "nccl_comm_state")
|
| 27 |
+
DEFINE_CONSTANT(comm_lib_version_key, "comm_lib_version")
|
| 28 |
+
DEFINE_CONSTANT(version_key, "version")
|
| 29 |
+
DEFINE_CONSTANT(pg_config_key, "pg_config")
|
| 30 |
+
DEFINE_CONSTANT(pg_status_key, "pg_status")
|
| 31 |
+
DEFINE_CONSTANT(record_id_key, "record_id")
|
| 32 |
+
DEFINE_CONSTANT(pg_id_key, "pg_id")
|
| 33 |
+
DEFINE_CONSTANT(pg_name_key, "process_group")
|
| 34 |
+
DEFINE_CONSTANT(collective_seq_id_key, "collective_seq_id")
|
| 35 |
+
DEFINE_CONSTANT(p2p_seq_id_key, "p2p_seq_id")
|
| 36 |
+
DEFINE_CONSTANT(is_p2p_key, "is_p2p")
|
| 37 |
+
DEFINE_CONSTANT(op_id_key, "op_id")
|
| 38 |
+
DEFINE_CONSTANT(profiling_name_key, "profiling_name")
|
| 39 |
+
DEFINE_CONSTANT(input_sizes_key, "input_sizes")
|
| 40 |
+
DEFINE_CONSTANT(input_dtypes_key, "input_dtypes")
|
| 41 |
+
DEFINE_CONSTANT(output_sizes_key, "output_sizes")
|
| 42 |
+
DEFINE_CONSTANT(output_dtypes_key, "output_dtypes")
|
| 43 |
+
DEFINE_CONSTANT(time_created_key, "time_created_ns")
|
| 44 |
+
DEFINE_CONSTANT(duration_key, "duration_ms")
|
| 45 |
+
DEFINE_CONSTANT(timeout_key, "timeout_ms")
|
| 46 |
+
DEFINE_CONSTANT(frames_key, "frames")
|
| 47 |
+
DEFINE_CONSTANT(state_key, "state")
|
| 48 |
+
DEFINE_CONSTANT(line_key, "line")
|
| 49 |
+
DEFINE_CONSTANT(name_key, "name")
|
| 50 |
+
DEFINE_CONSTANT(filename_key, "filename")
|
| 51 |
+
DEFINE_CONSTANT(retired_key, "retired")
|
| 52 |
+
DEFINE_CONSTANT(time_discovered_started_key, "time_discovered_started_ns")
|
| 53 |
+
DEFINE_CONSTANT(time_discovered_completed_key, "time_discovered_completed_ns")
|
| 54 |
+
DEFINE_CONSTANT(completed_state, "completed")
|
| 55 |
+
DEFINE_CONSTANT(scheduled_state, "scheduled")
|
| 56 |
+
DEFINE_CONSTANT(started_state, "started")
|
| 57 |
+
DEFINE_CONSTANT(thread_id_key, "thread_id")
|
| 58 |
+
DEFINE_CONSTANT(thread_name_key, "thread_name")
|
| 59 |
+
#undef DEFINE_CONSTANT
|
| 60 |
+
|
| 61 |
+
// Write NCCL debug info to local disk or any storage users define.
|
| 62 |
+
// There are some constrains we set for the debug info writer:
|
| 63 |
+
// 1. The writer should only be registered once.
|
| 64 |
+
// 2. Once registered, users cannot change it including un-register.
|
| 65 |
+
// 3. It is recommended to register the customized writer in the trainer setup,
|
| 66 |
+
// If users don't register before calling launchAsyncDebugDump, then users
|
| 67 |
+
// lose the chance to register (and the default writer will be
|
| 68 |
+
// auto-registered).
|
| 69 |
+
class TORCH_API DebugInfoWriter {
|
| 70 |
+
public:
|
| 71 |
+
virtual ~DebugInfoWriter() = default;
|
| 72 |
+
virtual void write(const std::string& trace);
|
| 73 |
+
static DebugInfoWriter& getWriter(int rank);
|
| 74 |
+
static void registerWriter(std::unique_ptr<DebugInfoWriter> writer);
|
| 75 |
+
virtual std::string getWriterTarget() {
|
| 76 |
+
return filename_;
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
protected:
|
| 80 |
+
DebugInfoWriter(
|
| 81 |
+
const std::string& namePrefix,
|
| 82 |
+
int rank,
|
| 83 |
+
bool enableDynamicFilename = false) {
|
| 84 |
+
filename_ = c10::str(namePrefix, rank);
|
| 85 |
+
enable_dynamic_filename_ = enableDynamicFilename;
|
| 86 |
+
rank_ = rank;
|
| 87 |
+
}
|
| 88 |
+
std::string filename_;
|
| 89 |
+
int rank_;
|
| 90 |
+
bool enable_dynamic_filename_;
|
| 91 |
+
|
| 92 |
+
private:
|
| 93 |
+
static std::unique_ptr<DebugInfoWriter> writer_;
|
| 94 |
+
static std::atomic<bool> hasWriterRegistered_;
|
| 95 |
+
};
|
| 96 |
+
|
| 97 |
+
template <typename EventType>
|
| 98 |
+
struct FlightRecorder {
|
| 99 |
+
static FlightRecorder<EventType>* get() {
|
| 100 |
+
// intentionally leak on exit
|
| 101 |
+
// because this will hold python state that may get destructed
|
| 102 |
+
static FlightRecorder<EventType>* instance =
|
| 103 |
+
new FlightRecorder<EventType>();
|
| 104 |
+
return instance;
|
| 105 |
+
}
|
| 106 |
+
FlightRecorder() {
|
| 107 |
+
// NOTE: This default value (2000) is duplicated in ProcessGroupNCCL.cpp
|
| 108 |
+
// and ProcessGroupNCCL.hpp because they cannot directly query max_entries_
|
| 109 |
+
// (no public accessor). Keep these values in sync.
|
| 110 |
+
max_entries_ = getCvarInt(
|
| 111 |
+
{"TORCH_FR_BUFFER_SIZE", "TORCH_NCCL_TRACE_BUFFER_SIZE"}, 2000);
|
| 112 |
+
capture_cpp_stack_ = getCvarBool(
|
| 113 |
+
{"TORCH_FR_CPP_STACK", "TORCH_NCCL_TRACE_CPP_STACK"}, false);
|
| 114 |
+
enabled_ = max_entries_ > 0;
|
| 115 |
+
reset_epoch_start_idx_[0] = 0;
|
| 116 |
+
}
|
| 117 |
+
struct Entry {
|
| 118 |
+
size_t id_; // incremented id in the trace buffer
|
| 119 |
+
// used to figure out where in the circular entries
|
| 120 |
+
// buffer this entry will be located to
|
| 121 |
+
// update state information
|
| 122 |
+
size_t reset_epoch_; // epoch when this entry was created
|
| 123 |
+
size_t pg_id_;
|
| 124 |
+
std::tuple<std::string, std::string> pg_name_; // <group_name, group_desc>
|
| 125 |
+
|
| 126 |
+
// collective_seq_id and p2p_seq_id refer to actual kernel launches (e.g. 1
|
| 127 |
+
// per coalesced group).
|
| 128 |
+
// collective_seq_id only increments for true collective operations (over
|
| 129 |
+
// all ranks in the group). p2p_seq_id only increments over non-collective
|
| 130 |
+
// operations in the group. op_id refers to logical operations (e.g. one per
|
| 131 |
+
// op inside coalesced group)
|
| 132 |
+
size_t collective_seq_id_;
|
| 133 |
+
size_t p2p_seq_id_;
|
| 134 |
+
size_t op_id_;
|
| 135 |
+
std::string profiling_name_;
|
| 136 |
+
|
| 137 |
+
std::shared_ptr<torch::CapturedTraceback> traceback_;
|
| 138 |
+
// we borrow pointers to start_ and end_ so we can query the state
|
| 139 |
+
// on reporting. However, once the event is completed, the call
|
| 140 |
+
// to `complete` will clear these.
|
| 141 |
+
EventType *start_, *end_;
|
| 142 |
+
|
| 143 |
+
// timestamp when the entry was created, likely close to the time the work
|
| 144 |
+
// was 'enqueued'- not necessarily started
|
| 145 |
+
c10::time_t time_created_;
|
| 146 |
+
|
| 147 |
+
// configured timeout for this entry
|
| 148 |
+
c10::time_t timeout_ms_;
|
| 149 |
+
|
| 150 |
+
// Is this a P2P event?
|
| 151 |
+
bool isP2P_;
|
| 152 |
+
|
| 153 |
+
std::optional<float> duration_;
|
| 154 |
+
|
| 155 |
+
// timestamp when our CPU threads discovered that the kernel started.
|
| 156 |
+
// will always be _after_ it actually started, and can be very late
|
| 157 |
+
// if the watchdog thread got stuck on CUDA APIs.
|
| 158 |
+
std::optional<c10::time_t> time_discovered_started_;
|
| 159 |
+
|
| 160 |
+
// timestamp when our CPU threads discovered that the kernel completed.
|
| 161 |
+
// will always be _after_ it actually completed, and can be the same time
|
| 162 |
+
// as the discovery of the start if the watchdog thread is stuck on CUDA
|
| 163 |
+
// APIs
|
| 164 |
+
std::optional<c10::time_t> time_discovered_completed_;
|
| 165 |
+
|
| 166 |
+
// size information for input/output tensors
|
| 167 |
+
c10::SmallVector<int64_t, 4> input_dims_;
|
| 168 |
+
std::vector<c10::ScalarType> input_dtypes_;
|
| 169 |
+
c10::SmallVector<int64_t, 4> output_dims_;
|
| 170 |
+
std::vector<c10::ScalarType> output_dtypes_;
|
| 171 |
+
c10::SmallVector<int64_t, 8> sizes_; // flattened from inputs, outputs
|
| 172 |
+
std::thread::id thread_id_;
|
| 173 |
+
std::string thread_name_;
|
| 174 |
+
bool retired_ = false; // is this work entry no longer in the workMetaList_?
|
| 175 |
+
// a retired but not completed event has timed out
|
| 176 |
+
|
| 177 |
+
// Returns the traceback of current entry, in string form.
|
| 178 |
+
// Note: `getTraceback` invokes `torch::symbolize`, which may need to
|
| 179 |
+
// acquire the GIL. If you don't want to block the current thread or take
|
| 180 |
+
// the risk of a GIL deadlock, you can use an asynchronous calling mechanism
|
| 181 |
+
// like std::async.
|
| 182 |
+
TORCH_API std::string getTraceback();
|
| 183 |
+
};
|
| 184 |
+
|
| 185 |
+
bool enabled_ = false;
|
| 186 |
+
bool capture_cpp_stack_ = false;
|
| 187 |
+
std::mutex mutex_;
|
| 188 |
+
std::vector<Entry> entries_;
|
| 189 |
+
size_t max_entries_ = 0;
|
| 190 |
+
size_t next_ = 0;
|
| 191 |
+
size_t id_ = 0;
|
| 192 |
+
size_t reset_epoch_ = 0;
|
| 193 |
+
std::unordered_map<size_t, size_t>
|
| 194 |
+
reset_epoch_start_idx_; // maps reset_epoch to the idx where it starts
|
| 195 |
+
std::map<size_t, std::shared_ptr<ProcessGroupStatus>> all_pg_status_;
|
| 196 |
+
std::map<std::tuple<std::string, std::string>, std::vector<uint64_t>>
|
| 197 |
+
pg_name_to_ranks_;
|
| 198 |
+
std::string comm_lib_version_;
|
| 199 |
+
|
| 200 |
+
struct TraceIdentifier {
|
| 201 |
+
std::optional<size_t> id;
|
| 202 |
+
std::optional<size_t> reset_epoch;
|
| 203 |
+
};
|
| 204 |
+
|
| 205 |
+
TraceIdentifier recordWithResetEnabled(
|
| 206 |
+
size_t pg_id,
|
| 207 |
+
const std::tuple<std::string, std::string>& pg_name,
|
| 208 |
+
size_t collective_seq_id,
|
| 209 |
+
size_t p2p_seq_id,
|
| 210 |
+
size_t op_id,
|
| 211 |
+
std::string profiling_name,
|
| 212 |
+
const std::vector<at::Tensor>& inputs,
|
| 213 |
+
const std::vector<at::Tensor>& outputs,
|
| 214 |
+
EventType* start,
|
| 215 |
+
EventType* end,
|
| 216 |
+
std::chrono::milliseconds timeout_ms,
|
| 217 |
+
std::shared_ptr<ProcessGroupStatus> pg_status,
|
| 218 |
+
bool isP2P);
|
| 219 |
+
|
| 220 |
+
std::optional<size_t> record(
|
| 221 |
+
size_t pg_id,
|
| 222 |
+
const std::tuple<std::string, std::string>& pg_name,
|
| 223 |
+
size_t collective_seq_id,
|
| 224 |
+
size_t p2p_seq_id,
|
| 225 |
+
size_t op_id,
|
| 226 |
+
std::string profiling_name,
|
| 227 |
+
const std::vector<at::Tensor>& inputs,
|
| 228 |
+
const std::vector<at::Tensor>& outputs,
|
| 229 |
+
EventType* start,
|
| 230 |
+
EventType* end,
|
| 231 |
+
std::chrono::milliseconds timeout_ms,
|
| 232 |
+
std::shared_ptr<ProcessGroupStatus> pg_status,
|
| 233 |
+
bool isP2P);
|
| 234 |
+
|
| 235 |
+
TORCH_API void record_pg_ranks(
|
| 236 |
+
const std::tuple<std::string, std::string>& pg_name,
|
| 237 |
+
std::vector<uint64_t> ranks);
|
| 238 |
+
|
| 239 |
+
void record_accelerator_version(const std::string comm_lib_version);
|
| 240 |
+
|
| 241 |
+
void update_state(Entry& r);
|
| 242 |
+
|
| 243 |
+
std::vector<Entry> dump_entries();
|
| 244 |
+
|
| 245 |
+
// Returns the index in entries_ for the given id and reset_epoch.
|
| 246 |
+
// Caller must hold mutex_lock before calling this method.
|
| 247 |
+
size_t getIdxFromId(size_t id, size_t reset_epoch) const;
|
| 248 |
+
|
| 249 |
+
// Returns the entry with the given id and reset_epoch, if it exists.
|
| 250 |
+
// Otherwise, returns std::nullopt.
|
| 251 |
+
TORCH_API std::optional<Entry> getEntry(
|
| 252 |
+
std::optional<size_t> id,
|
| 253 |
+
std::optional<size_t> reset_epoch);
|
| 254 |
+
|
| 255 |
+
TORCH_API std::optional<Entry> getEntry(std::optional<size_t> id);
|
| 256 |
+
|
| 257 |
+
/*
|
| 258 |
+
Mark an Event as completed and free its events.
|
| 259 |
+
This is called by the watchdog thread, and is asynchronous from the
|
| 260 |
+
perspective of the main thread.
|
| 261 |
+
compute_duration defaults to true since retire_id is only called in the
|
| 262 |
+
watchdog thread, which is currently a place we call cuda APIs which may hang,
|
| 263 |
+
but care should be taken to avoid computing duration in any function that must
|
| 264 |
+
never hang. (timing must also be enabled for compute_duration - see
|
| 265 |
+
TORCH_NCCL_ENABLE_TIMING).
|
| 266 |
+
*/
|
| 267 |
+
TORCH_API void retire_id(
|
| 268 |
+
std::optional<size_t> id,
|
| 269 |
+
std::optional<size_t> reset_epoch,
|
| 270 |
+
bool compute_duration = true);
|
| 271 |
+
|
| 272 |
+
TORCH_API void retire_id(
|
| 273 |
+
std::optional<size_t> id,
|
| 274 |
+
bool compute_duration = true);
|
| 275 |
+
|
| 276 |
+
TORCH_API void reset_all();
|
| 277 |
+
|
| 278 |
+
const c10::List<c10::IValue> getCollectiveTrace(
|
| 279 |
+
bool includeStacktraces,
|
| 280 |
+
bool onlyActive);
|
| 281 |
+
|
| 282 |
+
// dump pg_entries
|
| 283 |
+
const c10::Dict<c10::IValue, c10::IValue> getPgConfig();
|
| 284 |
+
|
| 285 |
+
const std::map<std::string, std::map<std::string, std::string>>
|
| 286 |
+
getPgConfigJson();
|
| 287 |
+
|
| 288 |
+
// dump pg_status
|
| 289 |
+
const c10::Dict<c10::IValue, c10::IValue> getPgStatus();
|
| 290 |
+
|
| 291 |
+
const std::map<std::string, std::map<std::string, std::string>>
|
| 292 |
+
getPgStatusJson();
|
| 293 |
+
|
| 294 |
+
std::string dump_json(
|
| 295 |
+
const std::optional<std::unordered_map<
|
| 296 |
+
std::string,
|
| 297 |
+
std::unordered_map<std::string, std::string>>>& extraDumpMap,
|
| 298 |
+
bool includeCollectives,
|
| 299 |
+
bool onlyActive);
|
| 300 |
+
|
| 301 |
+
std::string dump(
|
| 302 |
+
const std::optional<std::unordered_map<
|
| 303 |
+
std::string,
|
| 304 |
+
std::unordered_map<std::string, std::string>>>& extraDumpMap,
|
| 305 |
+
bool includeCollectives,
|
| 306 |
+
bool includeStackTraces,
|
| 307 |
+
bool onlyActive);
|
| 308 |
+
};
|
| 309 |
+
|
| 310 |
+
// Whether to include stack trace in the Flight Recorder trace (default true)
|
| 311 |
+
static std::vector<std::string> TORCH_INCLUDE_STACK_TRACE = {
|
| 312 |
+
"TORCH_INCLUDE_STACK_TRACE"};
|
| 313 |
+
|
| 314 |
+
// Whether to include only active collectives in the Flight Recorder trace
|
| 315 |
+
// (default false)
|
| 316 |
+
static std::vector<std::string> TORCH_INCLUDE_ONLY_ACTIVE = {
|
| 317 |
+
"TORCH_INCLUDE_ONLY_ACTIVE"};
|
| 318 |
+
|
| 319 |
+
// Dumps the fr traces and additional information about the Process
|
| 320 |
+
// Group.
|
| 321 |
+
TORCH_API std::string dump_fr_trace(
|
| 322 |
+
bool includeCollectives,
|
| 323 |
+
bool includeStackTraces,
|
| 324 |
+
bool onlyActive);
|
| 325 |
+
|
| 326 |
+
// Dumps the fr traces and additional information about the Process
|
| 327 |
+
// Group in JSON formatted string.
|
| 328 |
+
// We don't include stack traces in JSON format as it is far too much data.
|
| 329 |
+
TORCH_API std::string dump_fr_trace_json(
|
| 330 |
+
bool includeCollectives,
|
| 331 |
+
bool onlyActive);
|
| 332 |
+
} // namespace c10d
|
| 333 |
+
|
| 334 |
+
#else
|
| 335 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 336 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/FlightRecorderDetail.hpp
ADDED
|
@@ -0,0 +1,641 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#include <nlohmann/json.hpp>
|
| 3 |
+
|
| 4 |
+
#include <c10/util/WaitCounter.h>
|
| 5 |
+
#include <c10/util/thread_name.h>
|
| 6 |
+
|
| 7 |
+
#include <torch/csrc/distributed/c10d/FlightRecorder.hpp>
|
| 8 |
+
|
| 9 |
+
namespace c10d {
|
| 10 |
+
|
| 11 |
+
template <typename EventType>
|
| 12 |
+
float getDurationFromEvent(EventType& start, EventType& end);
|
| 13 |
+
|
| 14 |
+
// Returns the traceback of current entry, in string form.
|
| 15 |
+
// Note: `getTraceback` invokes `torch::symbolize`, which may need to acquire
|
| 16 |
+
// the GIL. If you don't want to block the current thread or take the risk of a
|
| 17 |
+
// GIL deadlock, you can use an asynchronous calling mechanism like std::async.
|
| 18 |
+
template <typename EventType>
|
| 19 |
+
std::string FlightRecorder<EventType>::Entry::getTraceback() {
|
| 20 |
+
torch::CapturedTraceback* traceback = traceback_.get();
|
| 21 |
+
torch::SymbolizedTracebacks s_tbs = torch::symbolize({traceback});
|
| 22 |
+
// We use 0 because we only have one traceback here.
|
| 23 |
+
const auto& s_tb = s_tbs.tracebacks.at(0);
|
| 24 |
+
std::stringstream oss;
|
| 25 |
+
for (auto idx : c10::irange(s_tb.size())) {
|
| 26 |
+
auto frame_id = s_tb[idx];
|
| 27 |
+
const auto& frame = s_tbs.all_frames.at(frame_id);
|
| 28 |
+
oss << '#' << idx << ' ' << frame.funcname << " from " << frame.filename
|
| 29 |
+
<< ':' << frame.lineno << '\n';
|
| 30 |
+
}
|
| 31 |
+
/* Resulted format is like:
|
| 32 |
+
#0 all_reduce from pytorch/torch/distributed/distributed_c10d.py:2696
|
| 33 |
+
#1 wrapper from pytorch/torch/distributed/c10d_logger.py:83
|
| 34 |
+
#2 bar from /home/user/repro.py:15
|
| 35 |
+
#3 foo from /home/user/repro.py:24
|
| 36 |
+
#4 main from /home/user/repro.py:34
|
| 37 |
+
#5 <module> from /home/user/repro.py:40
|
| 38 |
+
*/
|
| 39 |
+
return oss.str();
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
template <typename EventType>
|
| 43 |
+
std::optional<size_t> FlightRecorder<EventType>::record(
|
| 44 |
+
size_t pg_id,
|
| 45 |
+
const std::tuple<std::string, std::string>& pg_name,
|
| 46 |
+
size_t collective_seq_id,
|
| 47 |
+
size_t p2p_seq_id,
|
| 48 |
+
size_t op_id,
|
| 49 |
+
std::string profiling_name,
|
| 50 |
+
const std::vector<at::Tensor>& inputs,
|
| 51 |
+
const std::vector<at::Tensor>& outputs,
|
| 52 |
+
EventType* start,
|
| 53 |
+
EventType* end,
|
| 54 |
+
std::chrono::milliseconds timeout_ms,
|
| 55 |
+
std::shared_ptr<ProcessGroupStatus> pg_status,
|
| 56 |
+
bool isP2P) {
|
| 57 |
+
auto result = recordWithResetEnabled(
|
| 58 |
+
pg_id,
|
| 59 |
+
pg_name,
|
| 60 |
+
collective_seq_id,
|
| 61 |
+
p2p_seq_id,
|
| 62 |
+
op_id,
|
| 63 |
+
std::move(profiling_name),
|
| 64 |
+
inputs,
|
| 65 |
+
outputs,
|
| 66 |
+
start,
|
| 67 |
+
end,
|
| 68 |
+
timeout_ms,
|
| 69 |
+
std::move(pg_status),
|
| 70 |
+
isP2P);
|
| 71 |
+
return result.id;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
template <typename EventType>
|
| 75 |
+
typename FlightRecorder<EventType>::TraceIdentifier FlightRecorder<EventType>::
|
| 76 |
+
recordWithResetEnabled(
|
| 77 |
+
size_t pg_id,
|
| 78 |
+
const std::tuple<std::string, std::string>& pg_name,
|
| 79 |
+
size_t collective_seq_id,
|
| 80 |
+
size_t p2p_seq_id,
|
| 81 |
+
size_t op_id,
|
| 82 |
+
std::string profiling_name,
|
| 83 |
+
const std::vector<at::Tensor>& inputs,
|
| 84 |
+
const std::vector<at::Tensor>& outputs,
|
| 85 |
+
EventType* start,
|
| 86 |
+
EventType* end,
|
| 87 |
+
std::chrono::milliseconds timeout_ms,
|
| 88 |
+
std::shared_ptr<ProcessGroupStatus> pg_status,
|
| 89 |
+
bool isP2P) {
|
| 90 |
+
if (!enabled_) {
|
| 91 |
+
return TraceIdentifier{std::nullopt, std::nullopt};
|
| 92 |
+
}
|
| 93 |
+
auto traceback =
|
| 94 |
+
torch::CapturedTraceback::gather(true, true, capture_cpp_stack_);
|
| 95 |
+
std::lock_guard<std::mutex> guard(mutex_);
|
| 96 |
+
if (all_pg_status_.find(pg_id) == all_pg_status_.end()) {
|
| 97 |
+
// Current pg_status is not in FR.
|
| 98 |
+
all_pg_status_[pg_id] = std::move(pg_status);
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
TORCH_CHECK(
|
| 102 |
+
reset_epoch_start_idx_.find(reset_epoch_) !=
|
| 103 |
+
reset_epoch_start_idx_.end());
|
| 104 |
+
|
| 105 |
+
auto te = Entry{
|
| 106 |
+
id_,
|
| 107 |
+
reset_epoch_,
|
| 108 |
+
pg_id,
|
| 109 |
+
pg_name,
|
| 110 |
+
collective_seq_id,
|
| 111 |
+
p2p_seq_id,
|
| 112 |
+
op_id,
|
| 113 |
+
std::move(profiling_name),
|
| 114 |
+
std::move(traceback),
|
| 115 |
+
start,
|
| 116 |
+
end,
|
| 117 |
+
c10::getTime(),
|
| 118 |
+
timeout_ms.count(),
|
| 119 |
+
isP2P,
|
| 120 |
+
std::nullopt,
|
| 121 |
+
std::nullopt,
|
| 122 |
+
std::nullopt,
|
| 123 |
+
{},
|
| 124 |
+
{},
|
| 125 |
+
{},
|
| 126 |
+
{},
|
| 127 |
+
{},
|
| 128 |
+
std::this_thread::get_id(),
|
| 129 |
+
c10::getThreadName(),
|
| 130 |
+
false};
|
| 131 |
+
|
| 132 |
+
for (const auto& input : inputs) {
|
| 133 |
+
c10::IntArrayRef sizes = input.sizes();
|
| 134 |
+
te.input_dtypes_.push_back(input.dtype().toScalarType());
|
| 135 |
+
te.input_dims_.push_back(static_cast<int64_t>(sizes.size()));
|
| 136 |
+
te.sizes_.insert(te.sizes_.end(), sizes.begin(), sizes.end());
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
for (const auto& output : outputs) {
|
| 140 |
+
c10::IntArrayRef sizes = output.sizes();
|
| 141 |
+
te.output_dtypes_.push_back(output.dtype().toScalarType());
|
| 142 |
+
te.output_dims_.push_back(static_cast<int64_t>(sizes.size()));
|
| 143 |
+
te.sizes_.insert(te.sizes_.end(), sizes.begin(), sizes.end());
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
const auto next = next_++;
|
| 147 |
+
|
| 148 |
+
if (entries_.size() < max_entries_) {
|
| 149 |
+
entries_.emplace_back(std::move(te));
|
| 150 |
+
} else {
|
| 151 |
+
entries_[next] = std::move(te);
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
if (next_ == max_entries_) {
|
| 155 |
+
next_ = 0;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
const auto id = id_++;
|
| 159 |
+
return TraceIdentifier{id, reset_epoch_};
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
template <typename EventType>
|
| 163 |
+
void FlightRecorder<EventType>::record_pg_ranks(
|
| 164 |
+
const std::tuple<std::string, std::string>& pg_name,
|
| 165 |
+
std::vector<uint64_t> ranks) {
|
| 166 |
+
if (!enabled_) {
|
| 167 |
+
return;
|
| 168 |
+
}
|
| 169 |
+
std::lock_guard<std::mutex> guard(mutex_);
|
| 170 |
+
pg_name_to_ranks_[pg_name] = std::move(ranks);
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
template <typename EventType>
|
| 174 |
+
void FlightRecorder<EventType>::record_accelerator_version(
|
| 175 |
+
const std::string comm_lib_version) {
|
| 176 |
+
if (!enabled_) {
|
| 177 |
+
return;
|
| 178 |
+
}
|
| 179 |
+
std::lock_guard<std::mutex> guard(mutex_);
|
| 180 |
+
comm_lib_version_ = std::move(comm_lib_version);
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
template <typename EventType>
|
| 184 |
+
void FlightRecorder<EventType>::update_state(Entry& r) {
|
| 185 |
+
try {
|
| 186 |
+
if (r.start_ != nullptr) {
|
| 187 |
+
bool started = r.start_->query();
|
| 188 |
+
if (started && !r.time_discovered_started_) {
|
| 189 |
+
r.time_discovered_started_ = c10::getTime();
|
| 190 |
+
}
|
| 191 |
+
}
|
| 192 |
+
if (r.end_ != nullptr) {
|
| 193 |
+
bool completed = r.end_->query();
|
| 194 |
+
if (completed && !r.time_discovered_completed_) {
|
| 195 |
+
r.time_discovered_completed_ = c10::getTime();
|
| 196 |
+
}
|
| 197 |
+
}
|
| 198 |
+
} catch (std::exception& e) {
|
| 199 |
+
LOG(ERROR) << "Failed to update state for entry " << r.id_ << ": "
|
| 200 |
+
<< r.profiling_name_ << " with error: " << e.what();
|
| 201 |
+
}
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
template <typename EventType>
|
| 205 |
+
std::vector<typename FlightRecorder<EventType>::Entry> FlightRecorder<
|
| 206 |
+
EventType>::dump_entries() {
|
| 207 |
+
std::vector<Entry> result;
|
| 208 |
+
{
|
| 209 |
+
std::lock_guard<std::mutex> guard(mutex_);
|
| 210 |
+
// Filter entries during insertion - only keep entries from current epoch
|
| 211 |
+
auto filter = [this](const Entry& e) {
|
| 212 |
+
return e.reset_epoch_ == reset_epoch_;
|
| 213 |
+
};
|
| 214 |
+
std::copy_if(
|
| 215 |
+
entries_.begin() + static_cast<std::ptrdiff_t>(next_),
|
| 216 |
+
entries_.end(),
|
| 217 |
+
std::back_inserter(result),
|
| 218 |
+
filter);
|
| 219 |
+
std::copy_if(
|
| 220 |
+
entries_.begin(),
|
| 221 |
+
entries_.begin() + static_cast<std::ptrdiff_t>(next_),
|
| 222 |
+
std::back_inserter(result),
|
| 223 |
+
filter);
|
| 224 |
+
}
|
| 225 |
+
// query any remaining events
|
| 226 |
+
for (auto& r : result) {
|
| 227 |
+
update_state(r);
|
| 228 |
+
r.start_ = r.end_ = nullptr;
|
| 229 |
+
}
|
| 230 |
+
return result;
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
template <typename EventType>
|
| 234 |
+
// Returns the index in entries_ for the given id and reset_epoch.
|
| 235 |
+
// Caller must hold mutex_lock before calling this method.
|
| 236 |
+
size_t FlightRecorder<EventType>::getIdxFromId(size_t id, size_t reset_epoch)
|
| 237 |
+
const {
|
| 238 |
+
// Look up the starting idx for the given reset epoch
|
| 239 |
+
auto it = reset_epoch_start_idx_.find(reset_epoch);
|
| 240 |
+
TORCH_CHECK(it != reset_epoch_start_idx_.end());
|
| 241 |
+
// Calculate idx based on where the epoch started
|
| 242 |
+
return (it->second + id) % max_entries_;
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
template <typename EventType>
|
| 246 |
+
// Returns the entry with the given id and reset_epoch, if it exists. Otherwise,
|
| 247 |
+
// returns std::nullopt.
|
| 248 |
+
std::optional<typename FlightRecorder<EventType>::Entry> FlightRecorder<
|
| 249 |
+
EventType>::
|
| 250 |
+
getEntry(std::optional<size_t> id, std::optional<size_t> reset_epoch) {
|
| 251 |
+
if (!enabled_ || !id || !reset_epoch) {
|
| 252 |
+
return std::nullopt;
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
std::unique_lock<std::mutex> guard(mutex_);
|
| 256 |
+
Entry entry = entries_.at(getIdxFromId(*id, *reset_epoch));
|
| 257 |
+
if (entry.id_ == *id && entry.reset_epoch_ == *reset_epoch) {
|
| 258 |
+
return entry;
|
| 259 |
+
}
|
| 260 |
+
return std::nullopt;
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
template <typename EventType>
|
| 264 |
+
std::optional<typename FlightRecorder<EventType>::Entry> FlightRecorder<
|
| 265 |
+
EventType>::getEntry(std::optional<size_t> id) {
|
| 266 |
+
return getEntry(id, 0);
|
| 267 |
+
}
|
| 268 |
+
|
| 269 |
+
template <typename EventType>
|
| 270 |
+
void FlightRecorder<EventType>::retire_id(
|
| 271 |
+
std::optional<size_t> id,
|
| 272 |
+
std::optional<size_t> reset_epoch,
|
| 273 |
+
bool compute_duration) {
|
| 274 |
+
if (!enabled_ || !id || !reset_epoch) {
|
| 275 |
+
return;
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
bool can_compute_duration = false;
|
| 279 |
+
EventType* startEvent = nullptr;
|
| 280 |
+
EventType* endEvent = nullptr;
|
| 281 |
+
std::optional<float> duration = std::nullopt;
|
| 282 |
+
|
| 283 |
+
std::unique_lock<std::mutex> guard(mutex_);
|
| 284 |
+
|
| 285 |
+
Entry* entry = &entries_.at(getIdxFromId(*id, *reset_epoch));
|
| 286 |
+
if (entry->id_ == *id && entry->reset_epoch_ == *reset_epoch) {
|
| 287 |
+
update_state(*entry);
|
| 288 |
+
|
| 289 |
+
if (compute_duration) {
|
| 290 |
+
can_compute_duration = entry->time_discovered_completed_.has_value() &&
|
| 291 |
+
entry->start_ && entry->end_;
|
| 292 |
+
startEvent = entry->start_;
|
| 293 |
+
endEvent = entry->end_;
|
| 294 |
+
}
|
| 295 |
+
entry->retired_ = true;
|
| 296 |
+
entry->start_ = entry->end_ = nullptr;
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
if (can_compute_duration) {
|
| 300 |
+
// Compute duration without without holding the lock, because
|
| 301 |
+
// cudaEventDuration() can hang, and we need to acquire the lock before we
|
| 302 |
+
// can dump(), which we never want to block.
|
| 303 |
+
guard.unlock();
|
| 304 |
+
duration = getDurationFromEvent<EventType>(*startEvent, *endEvent);
|
| 305 |
+
guard.lock();
|
| 306 |
+
|
| 307 |
+
// Refresh the entry pointer, see if the entry has been overwritten
|
| 308 |
+
entry = &entries_.at(getIdxFromId(*id, *reset_epoch));
|
| 309 |
+
if (!(entry->id_ == *id && entry->reset_epoch_ == *reset_epoch)) {
|
| 310 |
+
LOG(INFO) << "retire_id abandoned for id " << *id
|
| 311 |
+
<< ", event was overwritten while waiting to compute duration.";
|
| 312 |
+
return;
|
| 313 |
+
}
|
| 314 |
+
if (duration.has_value()) {
|
| 315 |
+
entry->duration_ = duration;
|
| 316 |
+
}
|
| 317 |
+
}
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
template <typename EventType>
|
| 321 |
+
void FlightRecorder<EventType>::retire_id(
|
| 322 |
+
std::optional<size_t> id,
|
| 323 |
+
bool compute_duration) {
|
| 324 |
+
retire_id(id, 0, compute_duration);
|
| 325 |
+
}
|
| 326 |
+
|
| 327 |
+
template <typename EventType>
|
| 328 |
+
void FlightRecorder<EventType>::reset_all() {
|
| 329 |
+
std::lock_guard<std::mutex> guard(mutex_);
|
| 330 |
+
if (!entries_.empty()) {
|
| 331 |
+
// Soft delete: increment epoch to mark all existing entries as old
|
| 332 |
+
// Store where the new epoch starts in the circular buffer
|
| 333 |
+
reset_epoch_++;
|
| 334 |
+
reset_epoch_start_idx_[reset_epoch_] = next_;
|
| 335 |
+
id_ = 0;
|
| 336 |
+
}
|
| 337 |
+
}
|
| 338 |
+
|
| 339 |
+
template <typename EventType>
|
| 340 |
+
const c10::List<c10::IValue> FlightRecorder<EventType>::getCollectiveTrace(
|
| 341 |
+
bool includeStacktraces,
|
| 342 |
+
bool onlyActive) {
|
| 343 |
+
auto entries = new_list();
|
| 344 |
+
// Entries are returned in the order they were recorded
|
| 345 |
+
auto result = dump_entries();
|
| 346 |
+
std::vector<torch::CapturedTraceback*> tracebacks;
|
| 347 |
+
torch::SymbolizedTracebacks stracebacks;
|
| 348 |
+
std::vector<c10::IValue> all_frames;
|
| 349 |
+
if (includeStacktraces) {
|
| 350 |
+
for (auto& e : result) {
|
| 351 |
+
tracebacks.push_back(e.traceback_.get());
|
| 352 |
+
}
|
| 353 |
+
stracebacks = torch::symbolize(tracebacks);
|
| 354 |
+
for (const auto& f : stracebacks.all_frames) {
|
| 355 |
+
auto d = new_dict();
|
| 356 |
+
d.insert(name_key, f.funcname);
|
| 357 |
+
d.insert(filename_key, f.filename);
|
| 358 |
+
d.insert(line_key, int64_t(f.lineno));
|
| 359 |
+
all_frames.emplace_back(std::move(d));
|
| 360 |
+
}
|
| 361 |
+
}
|
| 362 |
+
for (auto i : c10::irange(result.size())) {
|
| 363 |
+
auto dict = new_dict();
|
| 364 |
+
auto& e = result.at(i);
|
| 365 |
+
// Skip completed events
|
| 366 |
+
if (onlyActive && e.time_discovered_completed_.has_value()) {
|
| 367 |
+
continue;
|
| 368 |
+
}
|
| 369 |
+
if (includeStacktraces) {
|
| 370 |
+
auto& tb = stracebacks.tracebacks.at(i);
|
| 371 |
+
auto frames = new_list();
|
| 372 |
+
for (auto frame : tb) {
|
| 373 |
+
frames.push_back(all_frames.at(frame));
|
| 374 |
+
}
|
| 375 |
+
dict.insert(frames_key, frames);
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
dict.insert(record_id_key, int64_t(e.id_));
|
| 379 |
+
dict.insert(pg_id_key, int64_t(e.pg_id_));
|
| 380 |
+
dict.insert(pg_name_key, e.pg_name_);
|
| 381 |
+
dict.insert(thread_name_key, e.thread_name_);
|
| 382 |
+
dict.insert(thread_id_key, c10::str(e.thread_id_));
|
| 383 |
+
dict.insert(collective_seq_id_key, int64_t(e.collective_seq_id_));
|
| 384 |
+
dict.insert(p2p_seq_id_key, int64_t(e.p2p_seq_id_));
|
| 385 |
+
dict.insert(op_id_key, int64_t(e.op_id_));
|
| 386 |
+
dict.insert(profiling_name_key, e.profiling_name_);
|
| 387 |
+
dict.insert(time_created_key, int64_t(e.time_created_));
|
| 388 |
+
if (e.duration_) {
|
| 389 |
+
dict.insert(duration_key, *e.duration_);
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
auto it = e.sizes_.begin();
|
| 393 |
+
auto read_sizes = [&](const c10::SmallVector<int64_t, 4>& dims) {
|
| 394 |
+
auto sizes = new_list();
|
| 395 |
+
for (auto dim : dims) {
|
| 396 |
+
auto arg_sizes = new_list();
|
| 397 |
+
for ([[maybe_unused]] auto i : c10::irange(dim)) {
|
| 398 |
+
arg_sizes.push_back(*it++);
|
| 399 |
+
}
|
| 400 |
+
sizes.push_back(arg_sizes);
|
| 401 |
+
}
|
| 402 |
+
return sizes;
|
| 403 |
+
};
|
| 404 |
+
|
| 405 |
+
dict.insert(input_sizes_key, read_sizes(e.input_dims_));
|
| 406 |
+
std::vector<std::string> input_dtypes_strs;
|
| 407 |
+
input_dtypes_strs.reserve(e.input_dtypes_.size());
|
| 408 |
+
for (const auto& input_dtype : e.input_dtypes_) {
|
| 409 |
+
input_dtypes_strs.emplace_back(c10::toString(input_dtype));
|
| 410 |
+
}
|
| 411 |
+
dict.insert(input_dtypes_key, input_dtypes_strs);
|
| 412 |
+
dict.insert(output_sizes_key, read_sizes(e.output_dims_));
|
| 413 |
+
std::vector<std::string> output_dtypes_strs;
|
| 414 |
+
output_dtypes_strs.reserve(e.output_dtypes_.size());
|
| 415 |
+
for (const auto& output_dtype : e.output_dtypes_) {
|
| 416 |
+
output_dtypes_strs.emplace_back(c10::toString(output_dtype));
|
| 417 |
+
}
|
| 418 |
+
dict.insert(output_dtypes_key, output_dtypes_strs);
|
| 419 |
+
if (e.time_discovered_completed_.has_value()) {
|
| 420 |
+
dict.insert(state_key, completed_state);
|
| 421 |
+
} else if (e.time_discovered_started_.has_value()) {
|
| 422 |
+
dict.insert(state_key, started_state);
|
| 423 |
+
} else {
|
| 424 |
+
dict.insert(state_key, scheduled_state);
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
dict.insert(
|
| 428 |
+
time_discovered_started_key,
|
| 429 |
+
e.time_discovered_started_.has_value()
|
| 430 |
+
? int64_t(*e.time_discovered_started_)
|
| 431 |
+
: c10::IValue());
|
| 432 |
+
dict.insert(
|
| 433 |
+
time_discovered_completed_key,
|
| 434 |
+
e.time_discovered_completed_.has_value()
|
| 435 |
+
? int64_t(*e.time_discovered_completed_)
|
| 436 |
+
: c10::IValue());
|
| 437 |
+
dict.insert(retired_key, e.retired_);
|
| 438 |
+
dict.insert(timeout_key, e.timeout_ms_);
|
| 439 |
+
dict.insert(is_p2p_key, e.isP2P_);
|
| 440 |
+
|
| 441 |
+
entries.push_back(dict);
|
| 442 |
+
}
|
| 443 |
+
return entries;
|
| 444 |
+
}
|
| 445 |
+
|
| 446 |
+
template <typename EventType>
|
| 447 |
+
const c10::Dict<c10::IValue, c10::IValue> FlightRecorder<
|
| 448 |
+
EventType>::getPgConfig() {
|
| 449 |
+
auto pg_config = new_dict();
|
| 450 |
+
for (const auto& [pg_name, ranks] : pg_name_to_ranks_) {
|
| 451 |
+
auto pg_info = new_dict();
|
| 452 |
+
pg_info.insert("name", std::get<0>(pg_name));
|
| 453 |
+
pg_info.insert("desc", std::get<1>(pg_name));
|
| 454 |
+
pg_info.insert("ranks", ranks_str(ranks));
|
| 455 |
+
pg_config.insert(std::get<0>(pg_name), pg_info);
|
| 456 |
+
}
|
| 457 |
+
return pg_config;
|
| 458 |
+
}
|
| 459 |
+
|
| 460 |
+
template <typename EventType>
|
| 461 |
+
const std::map<std::string, std::map<std::string, std::string>> FlightRecorder<
|
| 462 |
+
EventType>::getPgConfigJson() {
|
| 463 |
+
std::map<std::string, std::map<std::string, std::string>> result;
|
| 464 |
+
for (const auto& [pg_name, ranks] : pg_name_to_ranks_) {
|
| 465 |
+
auto pg_info = std::map<std::string, std::string>();
|
| 466 |
+
pg_info["name"] = std::get<0>(pg_name);
|
| 467 |
+
pg_info["desc"] = std::get<1>(pg_name);
|
| 468 |
+
pg_info["ranks"] = ranks_str(ranks);
|
| 469 |
+
result.emplace(std::get<0>(pg_name), pg_info);
|
| 470 |
+
}
|
| 471 |
+
return result;
|
| 472 |
+
}
|
| 473 |
+
|
| 474 |
+
template <typename EventType>
|
| 475 |
+
const c10::Dict<c10::IValue, c10::IValue> FlightRecorder<
|
| 476 |
+
EventType>::getPgStatus() {
|
| 477 |
+
auto all_pg_status = new_dict();
|
| 478 |
+
for (const auto& [pg_id, status] : all_pg_status_) {
|
| 479 |
+
auto pg_status = new_dict();
|
| 480 |
+
pg_status.insert("last_enqueued_collective", status->lastEnqueuedSeq);
|
| 481 |
+
pg_status.insert("last_started_collective", status->lastStartedSeq);
|
| 482 |
+
pg_status.insert("last_completed_collective", status->lastCompletedSeq);
|
| 483 |
+
all_pg_status.insert(std::to_string(pg_id), pg_status);
|
| 484 |
+
}
|
| 485 |
+
return all_pg_status;
|
| 486 |
+
}
|
| 487 |
+
|
| 488 |
+
template <typename EventType>
|
| 489 |
+
const std::map<std::string, std::map<std::string, std::string>> FlightRecorder<
|
| 490 |
+
EventType>::getPgStatusJson() {
|
| 491 |
+
std::map<std::string, std::map<std::string, std::string>> result;
|
| 492 |
+
for (const auto& [pg_id, status] : all_pg_status_) {
|
| 493 |
+
auto pg_status = std::map<std::string, std::string>();
|
| 494 |
+
pg_status["last_enqueued_collective"] =
|
| 495 |
+
std::to_string(status->lastEnqueuedSeq);
|
| 496 |
+
pg_status["last_started_collective"] =
|
| 497 |
+
std::to_string(status->lastStartedSeq);
|
| 498 |
+
pg_status["last_completed_collective"] =
|
| 499 |
+
std::to_string(status->lastCompletedSeq);
|
| 500 |
+
result[std::to_string(pg_id)] = pg_status;
|
| 501 |
+
}
|
| 502 |
+
return result;
|
| 503 |
+
}
|
| 504 |
+
|
| 505 |
+
using json = nlohmann::json;
|
| 506 |
+
template <typename EventType>
|
| 507 |
+
std::string FlightRecorder<EventType>::dump_json(
|
| 508 |
+
const std::optional<std::unordered_map<
|
| 509 |
+
std::string,
|
| 510 |
+
std::unordered_map<std::string, std::string>>>& extraDumpMap,
|
| 511 |
+
bool includeCollectives,
|
| 512 |
+
bool onlyActive) {
|
| 513 |
+
json result;
|
| 514 |
+
result[version_key_str] = version_val_str;
|
| 515 |
+
result[comm_lib_version_key_str] = comm_lib_version_;
|
| 516 |
+
result[pg_config_key_str] = getPgConfigJson();
|
| 517 |
+
result[pg_status_key_str] = getPgStatusJson();
|
| 518 |
+
|
| 519 |
+
// collective trace
|
| 520 |
+
if (includeCollectives) {
|
| 521 |
+
std::list<json> entries;
|
| 522 |
+
for (auto& e : dump_entries()) {
|
| 523 |
+
json j;
|
| 524 |
+
if (onlyActive && e.time_discovered_completed_.has_value()) {
|
| 525 |
+
continue;
|
| 526 |
+
}
|
| 527 |
+
j[record_id_key_str] = int64_t(e.id_);
|
| 528 |
+
j[pg_id_key_str] = int64_t(e.pg_id_);
|
| 529 |
+
j[pg_name_key_str] = e.pg_name_;
|
| 530 |
+
j[thread_name_key_str] = e.thread_name_;
|
| 531 |
+
j[thread_id_key_str] = c10::str(e.thread_id_);
|
| 532 |
+
j[collective_seq_id_key_str] = int64_t(e.collective_seq_id_);
|
| 533 |
+
j[p2p_seq_id_key_str] = int64_t(e.p2p_seq_id_);
|
| 534 |
+
j[op_id_key_str] = int64_t(e.op_id_);
|
| 535 |
+
j[profiling_name_key_str] = e.profiling_name_;
|
| 536 |
+
j[time_created_key_str] = int64_t(e.time_created_);
|
| 537 |
+
if (e.duration_) {
|
| 538 |
+
j[duration_key_str] = *e.duration_;
|
| 539 |
+
}
|
| 540 |
+
auto it = e.sizes_.begin();
|
| 541 |
+
auto read_sizes = [&](const c10::SmallVector<int64_t, 4>& dims) {
|
| 542 |
+
auto sizes = std::list<std::list<int64_t>>();
|
| 543 |
+
for (auto dim : dims) {
|
| 544 |
+
auto arg_sizes = std::list<int64_t>();
|
| 545 |
+
for (auto i : c10::irange(dim)) {
|
| 546 |
+
(void)i;
|
| 547 |
+
arg_sizes.push_back(*it++);
|
| 548 |
+
}
|
| 549 |
+
sizes.push_back(arg_sizes);
|
| 550 |
+
}
|
| 551 |
+
return sizes;
|
| 552 |
+
};
|
| 553 |
+
j[input_sizes_key_str] = read_sizes(e.input_dims_);
|
| 554 |
+
std::vector<std::string> input_dtypes_strs;
|
| 555 |
+
input_dtypes_strs.reserve(e.input_dtypes_.size());
|
| 556 |
+
for (const auto& input_dtype : e.input_dtypes_) {
|
| 557 |
+
input_dtypes_strs.emplace_back(c10::toString(input_dtype));
|
| 558 |
+
}
|
| 559 |
+
j[input_dtypes_key_str] = input_dtypes_strs;
|
| 560 |
+
j[output_sizes_key_str] = read_sizes(e.output_dims_);
|
| 561 |
+
std::vector<std::string> output_dtypes_strs;
|
| 562 |
+
output_dtypes_strs.reserve(e.output_dtypes_.size());
|
| 563 |
+
for (const auto& output_dtype : e.output_dtypes_) {
|
| 564 |
+
output_dtypes_strs.emplace_back(c10::toString(output_dtype));
|
| 565 |
+
}
|
| 566 |
+
j[output_dtypes_key_str] = output_dtypes_strs;
|
| 567 |
+
if (e.time_discovered_completed_.has_value()) {
|
| 568 |
+
j[state_key_str] = completed_state_str;
|
| 569 |
+
} else if (e.time_discovered_started_.has_value()) {
|
| 570 |
+
j[state_key_str] = started_state_str;
|
| 571 |
+
} else {
|
| 572 |
+
j[state_key_str] = scheduled_state_str;
|
| 573 |
+
}
|
| 574 |
+
j[time_discovered_started_key_str] =
|
| 575 |
+
e.time_discovered_started_.has_value()
|
| 576 |
+
? int64_t(*e.time_discovered_started_)
|
| 577 |
+
: 0;
|
| 578 |
+
j[time_discovered_completed_key_str] =
|
| 579 |
+
e.time_discovered_completed_.has_value()
|
| 580 |
+
? int64_t(*e.time_discovered_completed_)
|
| 581 |
+
: 0;
|
| 582 |
+
j[retired_key_str] = e.retired_;
|
| 583 |
+
j[timeout_key_str] = e.timeout_ms_;
|
| 584 |
+
j[is_p2p_key_str] = e.isP2P_;
|
| 585 |
+
entries.emplace_back(j);
|
| 586 |
+
}
|
| 587 |
+
|
| 588 |
+
if (!entries.empty()) {
|
| 589 |
+
result[entries_key_str] = entries;
|
| 590 |
+
}
|
| 591 |
+
}
|
| 592 |
+
|
| 593 |
+
if (extraDumpMap.has_value()) {
|
| 594 |
+
result[nccl_comm_key_str] = extraDumpMap.value();
|
| 595 |
+
}
|
| 596 |
+
return result.dump();
|
| 597 |
+
}
|
| 598 |
+
|
| 599 |
+
template <typename EventType>
|
| 600 |
+
std::string FlightRecorder<EventType>::dump(
|
| 601 |
+
const std::optional<std::unordered_map<
|
| 602 |
+
std::string,
|
| 603 |
+
std::unordered_map<std::string, std::string>>>& extraDumpMap,
|
| 604 |
+
bool includeCollectives,
|
| 605 |
+
bool includeStackTraces,
|
| 606 |
+
bool onlyActive) {
|
| 607 |
+
STATIC_SCOPED_WAIT_COUNTER(pytorch.wait_counter.FlightRecorder__dump);
|
| 608 |
+
auto result = new_dict();
|
| 609 |
+
// common values
|
| 610 |
+
result.insert(version_key, version_val);
|
| 611 |
+
result.insert(pg_config_key, getPgConfig());
|
| 612 |
+
result.insert(comm_lib_version_key_str, comm_lib_version_);
|
| 613 |
+
result.insert(pg_status_key, getPgStatus());
|
| 614 |
+
|
| 615 |
+
// collective trace
|
| 616 |
+
if (includeCollectives) {
|
| 617 |
+
result.insert(
|
| 618 |
+
entries_key, getCollectiveTrace(includeStackTraces, onlyActive));
|
| 619 |
+
}
|
| 620 |
+
|
| 621 |
+
// convert extraDumpMap into a dictionary
|
| 622 |
+
auto per_comm_dict = new_dict();
|
| 623 |
+
if (extraDumpMap.has_value()) {
|
| 624 |
+
for (const auto& [ncclId, ncclDump] : extraDumpMap.value()) {
|
| 625 |
+
auto inner_dict = new_dict();
|
| 626 |
+
for (const auto& [key, value] : ncclDump) {
|
| 627 |
+
inner_dict.insert(key, value);
|
| 628 |
+
}
|
| 629 |
+
per_comm_dict.insert(ncclId, inner_dict);
|
| 630 |
+
}
|
| 631 |
+
}
|
| 632 |
+
if (!per_comm_dict.empty()) {
|
| 633 |
+
result.insert(nccl_comm_key, per_comm_dict);
|
| 634 |
+
}
|
| 635 |
+
return pickle_str(result);
|
| 636 |
+
}
|
| 637 |
+
} // namespace c10d
|
| 638 |
+
|
| 639 |
+
#else
|
| 640 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 641 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Functional.hpp
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <torch/csrc/distributed/c10d/ProcessGroup.hpp>
|
| 5 |
+
|
| 6 |
+
namespace c10d {
|
| 7 |
+
|
| 8 |
+
C10_EXPORT at::Tensor& all_reduce_(
|
| 9 |
+
at::Tensor& input,
|
| 10 |
+
std::string reduce_op,
|
| 11 |
+
std::string group_name);
|
| 12 |
+
|
| 13 |
+
C10_EXPORT at::Tensor& all_reduce_(
|
| 14 |
+
at::Tensor& input,
|
| 15 |
+
std::string reduce_op,
|
| 16 |
+
c10::intrusive_ptr<ProcessGroup> group);
|
| 17 |
+
|
| 18 |
+
C10_EXPORT at::Tensor all_reduce(
|
| 19 |
+
const at::Tensor& input,
|
| 20 |
+
std::string reduce_op,
|
| 21 |
+
std::string group_name);
|
| 22 |
+
|
| 23 |
+
C10_EXPORT at::Tensor all_reduce(
|
| 24 |
+
const at::Tensor& input,
|
| 25 |
+
std::string reduce_op,
|
| 26 |
+
c10::intrusive_ptr<ProcessGroup> group);
|
| 27 |
+
|
| 28 |
+
C10_EXPORT std::vector<at::Tensor> all_reduce_coalesced_(
|
| 29 |
+
std::vector<at::Tensor> inputs,
|
| 30 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 31 |
+
std::string reduce_op,
|
| 32 |
+
c10::intrusive_ptr<ProcessGroup> group);
|
| 33 |
+
|
| 34 |
+
C10_EXPORT std::vector<at::Tensor> all_reduce_coalesced_(
|
| 35 |
+
std::vector<at::Tensor> inputs,
|
| 36 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 37 |
+
std::string reduce_op,
|
| 38 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 39 |
+
std::string group_name);
|
| 40 |
+
|
| 41 |
+
C10_EXPORT std::vector<at::Tensor> all_reduce_coalesced(
|
| 42 |
+
std::vector<at::Tensor> inputs,
|
| 43 |
+
std::string reduce_op,
|
| 44 |
+
c10::intrusive_ptr<ProcessGroup> group);
|
| 45 |
+
|
| 46 |
+
C10_EXPORT std::vector<at::Tensor> all_reduce_coalesced(
|
| 47 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 48 |
+
std::vector<at::Tensor> inputs,
|
| 49 |
+
std::string reduce_op,
|
| 50 |
+
std::string group_name);
|
| 51 |
+
|
| 52 |
+
C10_EXPORT std::vector<at::Tensor> all_gather_into_tensor_coalesced(
|
| 53 |
+
std::vector<at::Tensor> inputs,
|
| 54 |
+
int64_t group_size,
|
| 55 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 56 |
+
std::string group_name);
|
| 57 |
+
|
| 58 |
+
C10_EXPORT std::vector<at::Tensor> all_gather_into_tensor_coalesced(
|
| 59 |
+
std::vector<at::Tensor> inputs,
|
| 60 |
+
int64_t group_size,
|
| 61 |
+
c10::intrusive_ptr<ProcessGroup> group);
|
| 62 |
+
|
| 63 |
+
C10_EXPORT at::Tensor all_gather_into_tensor(
|
| 64 |
+
const at::Tensor& input,
|
| 65 |
+
int64_t group_size,
|
| 66 |
+
std::string group_name);
|
| 67 |
+
|
| 68 |
+
C10_EXPORT at::Tensor all_gather_into_tensor(
|
| 69 |
+
const at::Tensor& input,
|
| 70 |
+
int64_t group_size,
|
| 71 |
+
c10::intrusive_ptr<ProcessGroup> group);
|
| 72 |
+
|
| 73 |
+
C10_EXPORT at::Tensor& all_gather_into_tensor_out(
|
| 74 |
+
at::Tensor& input,
|
| 75 |
+
int64_t group_size,
|
| 76 |
+
const std::string& group_name,
|
| 77 |
+
at::Tensor& output);
|
| 78 |
+
|
| 79 |
+
C10_EXPORT at::Tensor& all_gather_into_tensor_out(
|
| 80 |
+
at::Tensor& input,
|
| 81 |
+
int64_t group_size,
|
| 82 |
+
c10::intrusive_ptr<ProcessGroup> group,
|
| 83 |
+
at::Tensor& output);
|
| 84 |
+
|
| 85 |
+
C10_EXPORT std::vector<at::Tensor> reduce_scatter_tensor_coalesced(
|
| 86 |
+
std::vector<at::Tensor> inputs,
|
| 87 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 88 |
+
std::string reduce_op,
|
| 89 |
+
int64_t group_size,
|
| 90 |
+
c10::intrusive_ptr<ProcessGroup> group);
|
| 91 |
+
|
| 92 |
+
C10_EXPORT std::vector<at::Tensor> reduce_scatter_tensor_coalesced(
|
| 93 |
+
std::vector<at::Tensor> inputs,
|
| 94 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 95 |
+
std::string reduce_op,
|
| 96 |
+
int64_t group_size,
|
| 97 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 98 |
+
std::string group_name);
|
| 99 |
+
|
| 100 |
+
C10_EXPORT at::Tensor reduce_scatter_tensor(
|
| 101 |
+
const at::Tensor& input,
|
| 102 |
+
std::string reduce_op,
|
| 103 |
+
int64_t group_size,
|
| 104 |
+
c10::intrusive_ptr<ProcessGroup> group);
|
| 105 |
+
|
| 106 |
+
C10_EXPORT at::Tensor reduce_scatter_tensor(
|
| 107 |
+
const at::Tensor& input,
|
| 108 |
+
std::string reduce_op,
|
| 109 |
+
int64_t group_size,
|
| 110 |
+
std::string group_name);
|
| 111 |
+
|
| 112 |
+
C10_EXPORT at::Tensor reduce_scatter_tensor_out(
|
| 113 |
+
const at::Tensor& input,
|
| 114 |
+
std::string reduce_op,
|
| 115 |
+
int64_t group_size,
|
| 116 |
+
c10::intrusive_ptr<ProcessGroup> group,
|
| 117 |
+
at::Tensor& output);
|
| 118 |
+
|
| 119 |
+
C10_EXPORT at::Tensor reduce_scatter_tensor_out(
|
| 120 |
+
const at::Tensor& input,
|
| 121 |
+
std::string reduce_op,
|
| 122 |
+
int64_t group_size,
|
| 123 |
+
std::string group_name,
|
| 124 |
+
at::Tensor& output);
|
| 125 |
+
|
| 126 |
+
C10_EXPORT at::Tensor all_to_all_single(
|
| 127 |
+
const at::Tensor& input,
|
| 128 |
+
at::SymIntArrayRef output_split_sizes,
|
| 129 |
+
at::SymIntArrayRef input_split_sizes,
|
| 130 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 131 |
+
std::string group_name);
|
| 132 |
+
|
| 133 |
+
C10_EXPORT at::Tensor all_to_all_single(
|
| 134 |
+
const at::Tensor& input,
|
| 135 |
+
at::SymIntArrayRef output_split_sizes,
|
| 136 |
+
at::SymIntArrayRef input_split_sizes,
|
| 137 |
+
c10::intrusive_ptr<ProcessGroup> group);
|
| 138 |
+
|
| 139 |
+
C10_EXPORT at::Tensor& broadcast_(
|
| 140 |
+
at::Tensor& input,
|
| 141 |
+
int64_t src,
|
| 142 |
+
c10::intrusive_ptr<ProcessGroup> group);
|
| 143 |
+
|
| 144 |
+
C10_EXPORT at::Tensor& broadcast_(
|
| 145 |
+
at::Tensor& input,
|
| 146 |
+
int64_t src,
|
| 147 |
+
std::string group_name);
|
| 148 |
+
|
| 149 |
+
C10_EXPORT at::Tensor broadcast(
|
| 150 |
+
const at::Tensor& input,
|
| 151 |
+
int64_t src,
|
| 152 |
+
c10::intrusive_ptr<ProcessGroup> group);
|
| 153 |
+
|
| 154 |
+
C10_EXPORT at::Tensor broadcast(
|
| 155 |
+
const at::Tensor& input,
|
| 156 |
+
int64_t src,
|
| 157 |
+
std::string group_name);
|
| 158 |
+
|
| 159 |
+
C10_EXPORT at::Tensor isend(
|
| 160 |
+
at::Tensor& send_buf,
|
| 161 |
+
int64_t dst,
|
| 162 |
+
int64_t tag,
|
| 163 |
+
std::string group_name);
|
| 164 |
+
|
| 165 |
+
C10_EXPORT at::Tensor irecv(
|
| 166 |
+
at::Tensor& recv_buf,
|
| 167 |
+
int64_t src,
|
| 168 |
+
int64_t tag,
|
| 169 |
+
std::string group_name);
|
| 170 |
+
|
| 171 |
+
C10_EXPORT std::vector<at::Tensor> batch_p2p_ops(
|
| 172 |
+
std::vector<std::string> op_list,
|
| 173 |
+
std::vector<int64_t> peer_list,
|
| 174 |
+
std::vector<int64_t> tag_list,
|
| 175 |
+
std::vector<at::Tensor> tensors_for_op,
|
| 176 |
+
std::string group_name);
|
| 177 |
+
|
| 178 |
+
} // namespace c10d
|
| 179 |
+
|
| 180 |
+
#else
|
| 181 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 182 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/GlooDeviceFactory.hpp
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#ifdef USE_C10D_GLOO
|
| 5 |
+
|
| 6 |
+
#include <string>
|
| 7 |
+
|
| 8 |
+
#include <c10/util/Registry.h>
|
| 9 |
+
#include <gloo/config.h>
|
| 10 |
+
#include <gloo/transport/device.h>
|
| 11 |
+
|
| 12 |
+
namespace c10d {
|
| 13 |
+
|
| 14 |
+
class TORCH_API GlooDeviceFactory {
|
| 15 |
+
public:
|
| 16 |
+
// Create new device instance for specific interface.
|
| 17 |
+
static std::shared_ptr<::gloo::transport::Device> makeDeviceForInterface(
|
| 18 |
+
const std::string& interface,
|
| 19 |
+
bool lazyInit);
|
| 20 |
+
|
| 21 |
+
// Create new device instance for specific hostname or address.
|
| 22 |
+
static std::shared_ptr<::gloo::transport::Device> makeDeviceForHostname(
|
| 23 |
+
const std::string& hostname,
|
| 24 |
+
bool lazyInit);
|
| 25 |
+
};
|
| 26 |
+
|
| 27 |
+
TORCH_DECLARE_SHARED_REGISTRY(
|
| 28 |
+
GlooDeviceRegistry,
|
| 29 |
+
::gloo::transport::Device,
|
| 30 |
+
const std::string&, /* interface */
|
| 31 |
+
const std::string&, /* hostname */
|
| 32 |
+
bool /* lazyInit */);
|
| 33 |
+
|
| 34 |
+
} // namespace c10d
|
| 35 |
+
|
| 36 |
+
#endif // USE_C10D_GLOO
|
| 37 |
+
|
| 38 |
+
#else
|
| 39 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 40 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/GroupRegistry.hpp
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <torch/csrc/distributed/c10d/ProcessGroup.hpp>
|
| 5 |
+
|
| 6 |
+
namespace c10d {
|
| 7 |
+
|
| 8 |
+
C10_EXPORT void set_thread_isolation_mode(bool enable);
|
| 9 |
+
|
| 10 |
+
bool get_thread_isolation_mode();
|
| 11 |
+
|
| 12 |
+
C10_EXPORT void register_process_group(
|
| 13 |
+
const std::string& group_name,
|
| 14 |
+
const c10::intrusive_ptr<c10d::ProcessGroup>& group);
|
| 15 |
+
|
| 16 |
+
C10_EXPORT c10::intrusive_ptr<c10d::ProcessGroup> resolve_process_group(
|
| 17 |
+
const std::string& group_name);
|
| 18 |
+
|
| 19 |
+
C10_EXPORT void unregister_process_group(const std::string& group_name);
|
| 20 |
+
|
| 21 |
+
C10_EXPORT void unregister_all_process_groups();
|
| 22 |
+
|
| 23 |
+
} // namespace c10d
|
| 24 |
+
|
| 25 |
+
#else
|
| 26 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 27 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/HashStore.hpp
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <condition_variable>
|
| 5 |
+
#include <mutex>
|
| 6 |
+
#include <unordered_map>
|
| 7 |
+
|
| 8 |
+
#include <torch/csrc/distributed/c10d/Store.hpp>
|
| 9 |
+
|
| 10 |
+
namespace c10d {
|
| 11 |
+
|
| 12 |
+
class TORCH_API HashStore : public Store {
|
| 13 |
+
public:
|
| 14 |
+
c10::intrusive_ptr<Store> clone() override;
|
| 15 |
+
|
| 16 |
+
~HashStore() override = default;
|
| 17 |
+
|
| 18 |
+
void set(const std::string& key, const std::vector<uint8_t>& data) override;
|
| 19 |
+
|
| 20 |
+
std::vector<uint8_t> compareSet(
|
| 21 |
+
const std::string& key,
|
| 22 |
+
const std::vector<uint8_t>& expectedValue,
|
| 23 |
+
const std::vector<uint8_t>& desiredValue) override;
|
| 24 |
+
|
| 25 |
+
std::vector<uint8_t> get(const std::string& key) override;
|
| 26 |
+
|
| 27 |
+
void wait(const std::vector<std::string>& keys) override {
|
| 28 |
+
wait(keys, timeout_);
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
void wait(
|
| 32 |
+
const std::vector<std::string>& keys,
|
| 33 |
+
const std::chrono::milliseconds& timeout) override;
|
| 34 |
+
|
| 35 |
+
int64_t add(const std::string& key, int64_t value) override;
|
| 36 |
+
|
| 37 |
+
int64_t getNumKeys() override;
|
| 38 |
+
|
| 39 |
+
bool check(const std::vector<std::string>& keys) override;
|
| 40 |
+
|
| 41 |
+
bool deleteKey(const std::string& key) override;
|
| 42 |
+
|
| 43 |
+
void append(const std::string& key, const std::vector<uint8_t>& value)
|
| 44 |
+
override;
|
| 45 |
+
|
| 46 |
+
std::vector<std::vector<uint8_t>> multiGet(
|
| 47 |
+
const std::vector<std::string>& keys) override;
|
| 48 |
+
|
| 49 |
+
void multiSet(
|
| 50 |
+
const std::vector<std::string>& keys,
|
| 51 |
+
const std::vector<std::vector<uint8_t>>& values) override;
|
| 52 |
+
|
| 53 |
+
// Returns true if this store support append, multiGet and multiSet
|
| 54 |
+
bool hasExtendedApi() const override;
|
| 55 |
+
|
| 56 |
+
void queuePush(const std::string& key, const std::vector<uint8_t>& value)
|
| 57 |
+
override;
|
| 58 |
+
|
| 59 |
+
std::vector<uint8_t> queuePop(const std::string& key, bool block) override;
|
| 60 |
+
|
| 61 |
+
int64_t queueLen(const std::string& key) override;
|
| 62 |
+
|
| 63 |
+
std::vector<std::string> listKeys() override;
|
| 64 |
+
|
| 65 |
+
protected:
|
| 66 |
+
bool checkLocked(
|
| 67 |
+
const std::unique_lock<std::mutex>& lock,
|
| 68 |
+
const std::vector<std::string>& keys);
|
| 69 |
+
|
| 70 |
+
void waitLocked(
|
| 71 |
+
std::unique_lock<std::mutex>& lock,
|
| 72 |
+
const std::vector<std::string>& keys,
|
| 73 |
+
const std::chrono::milliseconds& timeout);
|
| 74 |
+
|
| 75 |
+
protected:
|
| 76 |
+
std::unordered_map<std::string, std::vector<uint8_t>> map_;
|
| 77 |
+
std::unordered_map<std::string, std::deque<std::vector<uint8_t>>> queues_;
|
| 78 |
+
std::mutex m_;
|
| 79 |
+
std::condition_variable cv_;
|
| 80 |
+
};
|
| 81 |
+
|
| 82 |
+
} // namespace c10d
|
| 83 |
+
|
| 84 |
+
#else
|
| 85 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 86 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/NCCLUtils.hpp
ADDED
|
@@ -0,0 +1,458 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#ifdef USE_C10D_NCCL
|
| 5 |
+
|
| 6 |
+
#include <sched.h>
|
| 7 |
+
#include <cstdio>
|
| 8 |
+
#include <cstdlib>
|
| 9 |
+
|
| 10 |
+
#include <memory>
|
| 11 |
+
#include <mutex>
|
| 12 |
+
|
| 13 |
+
#include <ATen/ATen.h>
|
| 14 |
+
#include <ATen/cuda/CUDAEvent.h>
|
| 15 |
+
#include <c10/util/Exception.h>
|
| 16 |
+
#include <nccl.h>
|
| 17 |
+
#include <torch/csrc/cuda/nccl.h>
|
| 18 |
+
#include <optional>
|
| 19 |
+
|
| 20 |
+
constexpr int64_t kCommInitBusyWaitMillis = 2;
|
| 21 |
+
|
| 22 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 14, 0)
|
| 23 |
+
#define NCCL_HAS_COMM_NONBLOCKING
|
| 24 |
+
#endif
|
| 25 |
+
|
| 26 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 18, 0)
|
| 27 |
+
#define NCCL_HAS_COMM_SPLIT
|
| 28 |
+
#endif
|
| 29 |
+
|
| 30 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 23, 0)
|
| 31 |
+
#define NCCL_HAS_INIT_RANK_SCALABLE
|
| 32 |
+
#endif
|
| 33 |
+
|
| 34 |
+
// ncclGetLastError() is enabled only for NCCL versions 2.13+
|
| 35 |
+
// ncclRemoteError only exists in NCCL versions 2.13+
|
| 36 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 13, 0)
|
| 37 |
+
#define ENABLE_NCCL_GET_LAST_ERROR
|
| 38 |
+
#define NCCL_REMOTE_ERROR
|
| 39 |
+
#endif
|
| 40 |
+
|
| 41 |
+
static_assert(
|
| 42 |
+
NCCL_VERSION_CODE >= NCCL_VERSION(2, 7, 0),
|
| 43 |
+
"NCCL version must be 2.7 or later");
|
| 44 |
+
// The following macros represent features supported prior to NCCL 2.7,
|
| 45 |
+
// therefore we can define them unconditionally, given the static_assert above.
|
| 46 |
+
// TODO: remove these macros from code.
|
| 47 |
+
#define ENABLE_NCCL_ERROR_CHECKING
|
| 48 |
+
#define ENABLE_NCCL_P2P_SUPPORT
|
| 49 |
+
// End of macros for NCCL 2.7 and below.
|
| 50 |
+
|
| 51 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 11, 0)
|
| 52 |
+
#define ENABLE_NCCL_PREMUL_SUM_SUPPORT
|
| 53 |
+
#endif
|
| 54 |
+
|
| 55 |
+
// Note: the first version that supports ncclConfig_t is 2.14. Here we
|
| 56 |
+
// fast-forward the version requirement to 2.17 where ncclConfig_t has CTA and
|
| 57 |
+
// CGA fields because they have already been pybinded out.
|
| 58 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 17, 0)
|
| 59 |
+
#define NCCL_HAS_CONFIG
|
| 60 |
+
#endif
|
| 61 |
+
|
| 62 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 19, 0)
|
| 63 |
+
#define NCCL_HAS_COMM_REGISTER
|
| 64 |
+
#endif
|
| 65 |
+
|
| 66 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 27, 0)
|
| 67 |
+
#define NCCL_HAS_COMM_WINDOW_REGISTER
|
| 68 |
+
#endif
|
| 69 |
+
|
| 70 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 19, 0)
|
| 71 |
+
#define NCCL_HAS_MEM_ALLOC
|
| 72 |
+
#endif
|
| 73 |
+
|
| 74 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 26, 0)
|
| 75 |
+
#define NCCL_HAS_QOS
|
| 76 |
+
#endif
|
| 77 |
+
|
| 78 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 24, 0)
|
| 79 |
+
#define NCCL_SUPPORTS_FP8
|
| 80 |
+
#endif
|
| 81 |
+
|
| 82 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 27, 0)
|
| 83 |
+
#define NCCL_HAS_COLLNET
|
| 84 |
+
#endif
|
| 85 |
+
|
| 86 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 27, 0)
|
| 87 |
+
#define NCCL_HAS_CTA_POLICY
|
| 88 |
+
#endif
|
| 89 |
+
|
| 90 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 27, 0)
|
| 91 |
+
#define NCCL_HAS_NVLS_CTAS
|
| 92 |
+
#endif
|
| 93 |
+
|
| 94 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 27, 0)
|
| 95 |
+
#define NCCL_HAS_COMM_SHRINK
|
| 96 |
+
#endif
|
| 97 |
+
|
| 98 |
+
#if NCCL_VERSION_CODE >= NCCL_VERSION(2, 29, 7)
|
| 99 |
+
#define NCCL_HAS_COMM_OFFLOAD
|
| 100 |
+
#endif
|
| 101 |
+
|
| 102 |
+
// Macro to throw on a non-successful NCCL return value.
|
| 103 |
+
#define C10D_NCCL_CHECK(cmd, failureReason) \
|
| 104 |
+
do { \
|
| 105 |
+
ncclResult_t result = cmd; \
|
| 106 |
+
if (result != ncclSuccess) { \
|
| 107 |
+
std::string err = "NCCL error in: " + std::string(__FILE__) + ":" + \
|
| 108 |
+
std::to_string(__LINE__) + ", " + ncclGetErrorWithVersion(result) + \
|
| 109 |
+
"\n" + getNcclErrorDetailStr(result, failureReason); \
|
| 110 |
+
TORCH_CHECK_WITH(DistBackendError, false, err); \
|
| 111 |
+
} \
|
| 112 |
+
} while (0)
|
| 113 |
+
|
| 114 |
+
// Macro to throw on a non-successful NCCL return value for NONBLOCKING calls.
|
| 115 |
+
#define C10D_NCCL_CHECK_NONBLOCKING(cmd, failureReason) \
|
| 116 |
+
do { \
|
| 117 |
+
ncclResult_t result = cmd; \
|
| 118 |
+
if (result != ncclSuccess && result != ncclInProgress) { \
|
| 119 |
+
std::string err = "NCCL error in: " + std::string(__FILE__) + ":" + \
|
| 120 |
+
std::to_string(__LINE__) + ", " + ncclGetErrorWithVersion(result) + \
|
| 121 |
+
"\n" + getNcclErrorDetailStr(result, failureReason); \
|
| 122 |
+
TORCH_CHECK_WITH(DistBackendError, false, err); \
|
| 123 |
+
} \
|
| 124 |
+
} while (0)
|
| 125 |
+
|
| 126 |
+
// Error out if (current time - startTime) is greater than timeout (sec).
|
| 127 |
+
#define C10D_CHECK_TIMEOUT(startTime, timeout) \
|
| 128 |
+
do { \
|
| 129 |
+
auto currentTime = std::chrono::steady_clock::now(); \
|
| 130 |
+
auto timeElapsed = std::chrono::duration_cast<std::chrono::seconds>( \
|
| 131 |
+
currentTime - startTime) \
|
| 132 |
+
.count(); \
|
| 133 |
+
if (timeElapsed > timeout) { \
|
| 134 |
+
std::string err = "NCCL timeout in: " + std::string(__FILE__) + ":" + \
|
| 135 |
+
std::to_string(__LINE__); \
|
| 136 |
+
TORCH_CHECK_WITH(DistBackendError, false, err); \
|
| 137 |
+
} \
|
| 138 |
+
} while (0)
|
| 139 |
+
|
| 140 |
+
// Macro to throw on a non-successful NCCL return value, non-blocking.
|
| 141 |
+
// Thread-safe: uses NCCLComm wrapper's getAsyncError() which acquires mutex
|
| 142 |
+
// before calling ncclCommGetAsyncError to prevent race conditions between
|
| 143 |
+
// watchdog and main threads.
|
| 144 |
+
#define C10D_NCCL_CHECK_TIMEOUT_BASE( \
|
| 145 |
+
cmd, commWrapper, failureReason, yield_fn) \
|
| 146 |
+
do { \
|
| 147 |
+
ncclResult_t result = cmd; \
|
| 148 |
+
auto startTimepoint = std::chrono::steady_clock::now(); \
|
| 149 |
+
auto timeout = nccl_nonblocking_timeout(); \
|
| 150 |
+
while (result == ncclInProgress) { \
|
| 151 |
+
C10D_CHECK_TIMEOUT(startTimepoint, timeout); \
|
| 152 |
+
yield_fn; \
|
| 153 |
+
commWrapper->getAsyncError(&result); \
|
| 154 |
+
} \
|
| 155 |
+
if (result != ncclSuccess) { \
|
| 156 |
+
std::string err = "NCCL error in: " + std::string(__FILE__) + ":" + \
|
| 157 |
+
std::to_string(__LINE__) + ", " + ncclGetErrorWithVersion(result) + \
|
| 158 |
+
"\n" + getNcclErrorDetailStr(result, failureReason); \
|
| 159 |
+
TORCH_CHECK_WITH(DistBackendError, false, err); \
|
| 160 |
+
} \
|
| 161 |
+
} while (0)
|
| 162 |
+
|
| 163 |
+
// Sleep for kCommInitBusyWaitMillis milliseconds.
|
| 164 |
+
#define C10D_SCHED_SLEEP() \
|
| 165 |
+
std::this_thread::sleep_for( \
|
| 166 |
+
std::chrono::milliseconds(kCommInitBusyWaitMillis))
|
| 167 |
+
|
| 168 |
+
// Macro to throw exception on a non-successful NCCL return value or timeout.
|
| 169 |
+
// This macro uses sched_yield() to yield the CPU.
|
| 170 |
+
// Thus suitable for NCCL calls that would quickly turn ncclSuccess, e.g.
|
| 171 |
+
// collectives.
|
| 172 |
+
#define C10D_NCCL_CHECK_TIMEOUT(cmd, commWrapper, failureReason) \
|
| 173 |
+
C10D_NCCL_CHECK_TIMEOUT_BASE(cmd, commWrapper, failureReason, sched_yield())
|
| 174 |
+
|
| 175 |
+
// Macro to throw exception on a non-successful NCCL return value or timeout.
|
| 176 |
+
// This macro uses sleep to yield the CPU.
|
| 177 |
+
// Thus suitable for NCCL calls that would take longer to turn ncclSuccess, e.g.
|
| 178 |
+
// ncclCommInitRankConfig, ncclCommFinalize, etc.
|
| 179 |
+
#define C10D_NCCL_CHECK_TIMEOUT_SLEEP(cmd, commWrapper, failureReason) \
|
| 180 |
+
C10D_NCCL_CHECK_TIMEOUT_BASE( \
|
| 181 |
+
cmd, commWrapper, failureReason, C10D_SCHED_SLEEP())
|
| 182 |
+
|
| 183 |
+
#define C10D_NCCL_CHECK_TIMEOUT_GROUPEND(cmd, comm, failureReason) \
|
| 184 |
+
do { \
|
| 185 |
+
ncclResult_t state = cmd; \
|
| 186 |
+
auto startTimepoint = std::chrono::steady_clock::now(); \
|
| 187 |
+
auto timeout = nccl_nonblocking_timeout(); \
|
| 188 |
+
if (state == ncclInProgress) { \
|
| 189 |
+
do { \
|
| 190 |
+
C10D_CHECK_TIMEOUT(startTimepoint, timeout); \
|
| 191 |
+
sched_yield(); \
|
| 192 |
+
comm->getAsyncError(&state); \
|
| 193 |
+
} while (state == ncclInProgress); \
|
| 194 |
+
} \
|
| 195 |
+
if (state != ncclSuccess) { \
|
| 196 |
+
std::string err = "NCCL error in: " + std::string(__FILE__) + ":" + \
|
| 197 |
+
std::to_string(__LINE__) + ", " + ncclGetErrorWithVersion(state) + \
|
| 198 |
+
"\n" + getNcclErrorDetailStr(state, failureReason); \
|
| 199 |
+
TORCH_CHECK_WITH(DistBackendError, false, err); \
|
| 200 |
+
} \
|
| 201 |
+
} while (0)
|
| 202 |
+
|
| 203 |
+
// Macro to print and abort on a non-successful NCCL return value.
|
| 204 |
+
#define C10D_NCCL_ASSERT(cmd) \
|
| 205 |
+
do { \
|
| 206 |
+
ncclResult_t result = cmd; \
|
| 207 |
+
if (result != ncclSuccess) { \
|
| 208 |
+
std::string err = ncclGetErrorWithVersion(result); \
|
| 209 |
+
fprintf( \
|
| 210 |
+
stderr, \
|
| 211 |
+
"NCCL error in: %s:%d, %s\n", \
|
| 212 |
+
__FILE__, \
|
| 213 |
+
__LINE__, \
|
| 214 |
+
err.c_str()); \
|
| 215 |
+
abort(); \
|
| 216 |
+
} \
|
| 217 |
+
} while (0)
|
| 218 |
+
|
| 219 |
+
namespace c10d {
|
| 220 |
+
|
| 221 |
+
// NCCL type typing
|
| 222 |
+
static std::map<at::ScalarType, ncclDataType_t> ncclDataType = {
|
| 223 |
+
{at::kChar, ncclInt8},
|
| 224 |
+
{at::kByte, ncclUint8},
|
| 225 |
+
{at::kFloat, ncclFloat},
|
| 226 |
+
{at::kDouble, ncclDouble},
|
| 227 |
+
{at::kInt, ncclInt32},
|
| 228 |
+
{at::kLong, ncclInt64},
|
| 229 |
+
{at::kHalf, ncclHalf},
|
| 230 |
+
{at::kBool, ncclUint8},
|
| 231 |
+
#ifdef NCCL_SUPPORTS_FP8
|
| 232 |
+
{at::kFloat8_e5m2, ncclFloat8e5m2},
|
| 233 |
+
{at::kFloat8_e4m3fn, ncclFloat8e4m3},
|
| 234 |
+
#else
|
| 235 |
+
{at::kFloat8_e5m2, ncclUint8},
|
| 236 |
+
{at::kFloat8_e4m3fn, ncclUint8},
|
| 237 |
+
#endif
|
| 238 |
+
// NVIDIA GPUs does not support the UZ version standing for "no negative
|
| 239 |
+
// zero". See https://onnx.ai/onnx/technical/float8.html
|
| 240 |
+
{at::kFloat8_e4m3fnuz, ncclUint8},
|
| 241 |
+
{at::kFloat8_e5m2fnuz, ncclUint8},
|
| 242 |
+
#if HAS_NCCL_BF16_DATATYPE
|
| 243 |
+
{at::kBFloat16, ncclBfloat16},
|
| 244 |
+
#endif // HAS_NCCL_BF16_DATATYPE
|
| 245 |
+
};
|
| 246 |
+
|
| 247 |
+
TORCH_API size_t hashTensors(const std::vector<at::Tensor>& tensors);
|
| 248 |
+
TORCH_API std::string getNcclVersion();
|
| 249 |
+
TORCH_API std::tuple<int, int, int> getNcclVersionTuple();
|
| 250 |
+
TORCH_API int getNcclVersionNumber();
|
| 251 |
+
TORCH_API std::string ncclGetErrorWithVersion(ncclResult_t error);
|
| 252 |
+
int nccl_nonblocking_timeout();
|
| 253 |
+
|
| 254 |
+
// Provides additional detail into NCCL error codes based on when these are
|
| 255 |
+
// thrown in the NCCL codebase.
|
| 256 |
+
TORCH_API std::string getNcclErrorDetailStr(
|
| 257 |
+
ncclResult_t error,
|
| 258 |
+
std::optional<std::string> processGroupFailureReason = std::nullopt);
|
| 259 |
+
|
| 260 |
+
// Helper function that gets the data type and issues error if not supported
|
| 261 |
+
ncclDataType_t getNcclDataType(at::ScalarType type);
|
| 262 |
+
|
| 263 |
+
// RAII wrapper for NCCL communicator
|
| 264 |
+
class NCCLComm {
|
| 265 |
+
using MutexType = std::recursive_mutex;
|
| 266 |
+
using LockType = std::unique_lock<MutexType>;
|
| 267 |
+
|
| 268 |
+
public:
|
| 269 |
+
explicit NCCLComm(ncclComm_t ncclComm);
|
| 270 |
+
|
| 271 |
+
NCCLComm() = default;
|
| 272 |
+
|
| 273 |
+
~NCCLComm() noexcept;
|
| 274 |
+
|
| 275 |
+
void setUniqueHash(ncclUniqueId ncclId);
|
| 276 |
+
void setUniqueHash(std::string hash);
|
| 277 |
+
std::string getUniqueHash();
|
| 278 |
+
|
| 279 |
+
static std::shared_ptr<NCCLComm> create(
|
| 280 |
+
int numRanks,
|
| 281 |
+
int rank,
|
| 282 |
+
ncclUniqueId commId,
|
| 283 |
+
at::DeviceIndex deviceIndex);
|
| 284 |
+
|
| 285 |
+
#ifdef NCCL_HAS_CONFIG
|
| 286 |
+
static std::shared_ptr<NCCLComm> create(
|
| 287 |
+
int numRanks,
|
| 288 |
+
int rank,
|
| 289 |
+
ncclUniqueId commId,
|
| 290 |
+
at::DeviceIndex deviceIndex,
|
| 291 |
+
ncclConfig_t& config);
|
| 292 |
+
#ifdef NCCL_HAS_INIT_RANK_SCALABLE
|
| 293 |
+
static std::shared_ptr<NCCLComm> create_scalable(
|
| 294 |
+
int numRanks,
|
| 295 |
+
int rank,
|
| 296 |
+
std::vector<ncclUniqueId>& commIds,
|
| 297 |
+
at::DeviceIndex deviceIndex,
|
| 298 |
+
ncclConfig_t& config);
|
| 299 |
+
#endif // NCCL_HAS_INIT_RANK_SCALABLE
|
| 300 |
+
#endif // NCCL_HAS_CONFIG
|
| 301 |
+
|
| 302 |
+
#ifdef NCCL_HAS_COMM_SPLIT
|
| 303 |
+
static std::shared_ptr<NCCLComm> split(
|
| 304 |
+
NCCLComm* source,
|
| 305 |
+
int color_id,
|
| 306 |
+
int rank,
|
| 307 |
+
ncclConfig_t& config);
|
| 308 |
+
#endif // NCCL_HAS_COMM_SPLIT
|
| 309 |
+
|
| 310 |
+
#ifdef NCCL_HAS_COMM_SHRINK
|
| 311 |
+
static std::shared_ptr<NCCLComm> shrink(
|
| 312 |
+
NCCLComm* source,
|
| 313 |
+
std::vector<int>& ranks_to_exclude,
|
| 314 |
+
ncclConfig_t* config,
|
| 315 |
+
int shrinkFlags = 0);
|
| 316 |
+
#endif // NCCL_HAS_COMM_SHRINK
|
| 317 |
+
|
| 318 |
+
#if (defined(IS_NCCLX) || defined(USE_ROCM)) && defined(NCCL_COMM_DUMP)
|
| 319 |
+
std::unordered_map<std::string, std::string> ncclCommDump();
|
| 320 |
+
#endif
|
| 321 |
+
|
| 322 |
+
at::DeviceIndex getDeviceIndex();
|
| 323 |
+
|
| 324 |
+
// Must not be copyable
|
| 325 |
+
NCCLComm(const NCCLComm&) = delete;
|
| 326 |
+
NCCLComm& operator=(const NCCLComm&) = delete;
|
| 327 |
+
|
| 328 |
+
// Do not support move assignment as there is no valid use case
|
| 329 |
+
NCCLComm& operator=(NCCLComm&& other) = delete;
|
| 330 |
+
|
| 331 |
+
// Move constructable
|
| 332 |
+
// NOLINTNEXTLINE(*-noexcept-move-*)
|
| 333 |
+
NCCLComm(NCCLComm&& other);
|
| 334 |
+
|
| 335 |
+
ncclComm_t getNcclComm();
|
| 336 |
+
|
| 337 |
+
// Wait for the communicator to be ready. This is a blocking function.
|
| 338 |
+
// Useful in nonblocking mode: NCCL requires the communicator to be ready
|
| 339 |
+
// before issuing a second command.
|
| 340 |
+
// Arguments:
|
| 341 |
+
// longInterval: if true, wait with sleep of an interval; otherwise, wait
|
| 342 |
+
// with `sched_yield` which is faster (but acquires CPU more frequently).
|
| 343 |
+
// Use `longInterval=true` when waiting for initialization or finalize to
|
| 344 |
+
// complete. Use `longInterval=false` when waiting collective call to return
|
| 345 |
+
// ncclSuccess.
|
| 346 |
+
void waitReady(bool longInterval);
|
| 347 |
+
|
| 348 |
+
std::optional<std::string> getNcclCommFailureReason() const;
|
| 349 |
+
|
| 350 |
+
void abort(std::optional<std::string> commFailureReason = std::nullopt);
|
| 351 |
+
|
| 352 |
+
// Finalize a communicator -- asking it to flush its operations. When the
|
| 353 |
+
// communicator is marked as nonblocking, this is a nonblocking function;
|
| 354 |
+
// otherwise, it will block till all operations complete.
|
| 355 |
+
void finalize();
|
| 356 |
+
|
| 357 |
+
// Destroy a communicator. This is a blocking function.
|
| 358 |
+
void destroy();
|
| 359 |
+
|
| 360 |
+
bool isInitialized() const;
|
| 361 |
+
|
| 362 |
+
bool isAborted() const;
|
| 363 |
+
|
| 364 |
+
uint64_t getCommSplitCounter() const;
|
| 365 |
+
|
| 366 |
+
ncclResult_t checkForNcclError();
|
| 367 |
+
|
| 368 |
+
// Thread-safe wrapper for ncclCommGetAsyncError that acquires the mutex
|
| 369 |
+
// before calling the NCCL API. This is needed because NCCL does not provide
|
| 370 |
+
// thread-safety guarantees for ncclCommGetAsyncError, and both the main
|
| 371 |
+
// thread and watchdog thread may call it concurrently.
|
| 372 |
+
ncclResult_t getAsyncError(ncclResult_t* asyncError);
|
| 373 |
+
|
| 374 |
+
ncclResult_t registerSegment(
|
| 375 |
+
void* ptr,
|
| 376 |
+
size_t size,
|
| 377 |
+
bool errorOnRereg = true,
|
| 378 |
+
bool window = false);
|
| 379 |
+
|
| 380 |
+
ncclResult_t deregisterSegment(void* ptr, bool window = false);
|
| 381 |
+
|
| 382 |
+
std::string repr() const;
|
| 383 |
+
|
| 384 |
+
// APIs related to memory offload (require NCCL 2.29.7+ at runtime)
|
| 385 |
+
void suspend();
|
| 386 |
+
|
| 387 |
+
void resume();
|
| 388 |
+
|
| 389 |
+
std::unordered_map<std::string, uint64_t> getMemoryStats();
|
| 390 |
+
|
| 391 |
+
friend class ProcessGroupNCCL;
|
| 392 |
+
|
| 393 |
+
protected:
|
| 394 |
+
// Unique hash for this communicator.
|
| 395 |
+
std::string uniqueHash_;
|
| 396 |
+
bool aborted_{false};
|
| 397 |
+
uint64_t ncclCommSplitCounter_{0};
|
| 398 |
+
ncclResult_t ncclAsyncErr_{ncclSuccess};
|
| 399 |
+
mutable MutexType mutex_;
|
| 400 |
+
// Rank that this communicator corresponds to.
|
| 401 |
+
int rank_{};
|
| 402 |
+
// Optional reason for communicator failure, provided by ProcessGroupNCCL for
|
| 403 |
+
// better error messaging.
|
| 404 |
+
std::optional<std::string> commFailureReason_;
|
| 405 |
+
bool initialized_{false};
|
| 406 |
+
// Whether this communicator is using nonblocking mode. Recorded during comm
|
| 407 |
+
// creation or split. For safety, we give a default value of true (more
|
| 408 |
+
// protection).
|
| 409 |
+
bool nonBlocking_{true};
|
| 410 |
+
// Device index for which the NCCL comm is created
|
| 411 |
+
at::DeviceIndex deviceIndex_{-1};
|
| 412 |
+
#ifdef NCCL_HAS_COMM_REGISTER
|
| 413 |
+
// Stores handlers for tensors registered by NCCL
|
| 414 |
+
std::unordered_map<void*, void*> registeredSegmentHandles_;
|
| 415 |
+
#endif // NCCL_HAS_COMM_REGISTER
|
| 416 |
+
|
| 417 |
+
private:
|
| 418 |
+
ncclComm_t ncclComm_{nullptr};
|
| 419 |
+
};
|
| 420 |
+
|
| 421 |
+
// Helper that automatically cleans up premul sums.
|
| 422 |
+
struct ncclRedOpRAII {
|
| 423 |
+
ncclRedOpRAII() = default;
|
| 424 |
+
ncclRedOpRAII(ncclRedOp_t op) : op_(op) {}
|
| 425 |
+
ncclRedOpRAII(ncclRedOp_t op, ncclComm_t comm)
|
| 426 |
+
: op_(op), comm_(comm), premul_sum_(true) {}
|
| 427 |
+
ncclRedOpRAII(const ncclRedOpRAII&) = delete;
|
| 428 |
+
ncclRedOpRAII& operator=(const ncclRedOpRAII&) = delete;
|
| 429 |
+
ncclRedOpRAII(ncclRedOpRAII&& tmp) noexcept : ncclRedOpRAII() {
|
| 430 |
+
std::swap(tmp.op_, this->op_);
|
| 431 |
+
std::swap(tmp.comm_, this->comm_);
|
| 432 |
+
std::swap(tmp.premul_sum_, this->premul_sum_);
|
| 433 |
+
}
|
| 434 |
+
#if defined(ENABLE_NCCL_PREMUL_SUM_SUPPORT)
|
| 435 |
+
~ncclRedOpRAII() {
|
| 436 |
+
if (premul_sum_) {
|
| 437 |
+
ncclRedOpDestroy(op_, comm_);
|
| 438 |
+
}
|
| 439 |
+
}
|
| 440 |
+
#endif // ENABLE_NCCL_PREMUL_SUM_SUPPORT
|
| 441 |
+
operator ncclRedOp_t() const {
|
| 442 |
+
return op_;
|
| 443 |
+
}
|
| 444 |
+
ncclRedOp_t op_{};
|
| 445 |
+
ncclComm_t comm_{};
|
| 446 |
+
bool premul_sum_ = false;
|
| 447 |
+
};
|
| 448 |
+
|
| 449 |
+
void printNcclCommProxyTrace(
|
| 450 |
+
const std::string& dumpReason,
|
| 451 |
+
const std::unordered_map<std::string, std::string>& dumpMap);
|
| 452 |
+
} // namespace c10d
|
| 453 |
+
|
| 454 |
+
#endif // USE_C10D_NCCL
|
| 455 |
+
|
| 456 |
+
#else
|
| 457 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 458 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/NanCheck.hpp
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <ATen/ATen.h>
|
| 5 |
+
#include <torch/csrc/Export.h>
|
| 6 |
+
|
| 7 |
+
namespace c10d {
|
| 8 |
+
|
| 9 |
+
// Check for NaNs in a tensor. If any are found, throw an error.
|
| 10 |
+
// Dispatches to device-specific implementations via the c10d::check_for_nan op.
|
| 11 |
+
TORCH_API void checkForNan(const at::Tensor& tensor);
|
| 12 |
+
|
| 13 |
+
} // namespace c10d
|
| 14 |
+
|
| 15 |
+
#else
|
| 16 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 17 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ParamCommsUtils.hpp
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <ATen/core/ivalue.h>
|
| 5 |
+
#include <ATen/record_function.h>
|
| 6 |
+
#include <c10/macros/Macros.h>
|
| 7 |
+
#include <c10/util/ThreadLocalDebugInfo.h>
|
| 8 |
+
#include <string>
|
| 9 |
+
#include <tuple>
|
| 10 |
+
#include <vector>
|
| 11 |
+
|
| 12 |
+
namespace torch {
|
| 13 |
+
|
| 14 |
+
class TORCH_API ParamCommsDebugInfo : public c10::DebugInfoBase {
|
| 15 |
+
public:
|
| 16 |
+
ParamCommsDebugInfo() = default;
|
| 17 |
+
ParamCommsDebugInfo(
|
| 18 |
+
std::tuple<std::string, std::string> pgName,
|
| 19 |
+
int rank,
|
| 20 |
+
std::string&& collName,
|
| 21 |
+
int64_t inNelems,
|
| 22 |
+
int64_t outNelems,
|
| 23 |
+
at::ScalarType dType,
|
| 24 |
+
std::vector<int64_t> inSplitSizes,
|
| 25 |
+
std::vector<int64_t> outSplitSizes,
|
| 26 |
+
int globalRankStart,
|
| 27 |
+
int globalRankStride,
|
| 28 |
+
int worldSize,
|
| 29 |
+
bool isAsynchronizedOp = true);
|
| 30 |
+
|
| 31 |
+
~ParamCommsDebugInfo() override = default;
|
| 32 |
+
|
| 33 |
+
const std::string getProcessGroupName() const {
|
| 34 |
+
return std::get<0>(pgName_);
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
const std::string getProcessGroupDesc() const {
|
| 38 |
+
return std::get<1>(pgName_);
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
int getRank() const {
|
| 42 |
+
return rank_;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
int getWorldSize() const {
|
| 46 |
+
return worldSize_;
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
int getGlobalRankStart() const {
|
| 50 |
+
return globalRankStart_;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
int getGlobalRankStride() const {
|
| 54 |
+
return globalRankStride_;
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
const std::string getCollectiveName() const {
|
| 58 |
+
return collectiveName_;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
int64_t getInMessageNelems() const {
|
| 62 |
+
return inMessageNelems_;
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
int64_t getOutMessageNelems() const {
|
| 66 |
+
return outMessageNelems_;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
at::ScalarType getDType() const {
|
| 70 |
+
return dType_;
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
const std::vector<int64_t>& getInputSplitSizes() const {
|
| 74 |
+
return inputSplitSizes_;
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
const std::vector<int64_t>& getOutputSplitSizes() const {
|
| 78 |
+
return outputSplitSizes_;
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
const std::vector<int64_t>& getGroupRanks() const {
|
| 82 |
+
return groupRanks_;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
bool isAsynchronizedOp() const {
|
| 86 |
+
return isAsynchronizedOp_;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
int64_t getSequenceNumber() const {
|
| 90 |
+
return sequenceNumber_;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
bool getIsP2P() const {
|
| 94 |
+
return isP2P_;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
void setSequenceInfo(int64_t seqNum, bool isP2P) {
|
| 98 |
+
sequenceNumber_ = seqNum;
|
| 99 |
+
isP2P_ = isP2P;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
private:
|
| 103 |
+
std::tuple<std::string, std::string> pgName_; // <group_name, group_desc>
|
| 104 |
+
int rank_{};
|
| 105 |
+
int worldSize_{};
|
| 106 |
+
std::string collectiveName_;
|
| 107 |
+
int64_t inMessageNelems_{};
|
| 108 |
+
int64_t outMessageNelems_{};
|
| 109 |
+
at::ScalarType dType_ = at::kByte;
|
| 110 |
+
std::vector<int64_t> inputSplitSizes_;
|
| 111 |
+
std::vector<int64_t> outputSplitSizes_;
|
| 112 |
+
int globalRankStart_{};
|
| 113 |
+
int globalRankStride_{};
|
| 114 |
+
std::vector<int64_t> groupRanks_;
|
| 115 |
+
bool isAsynchronizedOp_{};
|
| 116 |
+
int64_t sequenceNumber_{-1};
|
| 117 |
+
bool isP2P_{false};
|
| 118 |
+
};
|
| 119 |
+
|
| 120 |
+
// Helper to set sequence info from tuple-typed seq arguments (NCCL backend).
|
| 121 |
+
// No-op fallback for backends that pass non-tuple seq types (e.g., XPU/XCCL).
|
| 122 |
+
template <typename A, typename B>
|
| 123 |
+
inline void maybeSetSequenceInfo(
|
| 124 |
+
const std::shared_ptr<ParamCommsDebugInfo>& info,
|
| 125 |
+
const std::tuple<A, B>& seq) {
|
| 126 |
+
info->setSequenceInfo(std::get<0>(seq), std::get<1>(seq));
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
template <typename T>
|
| 130 |
+
inline void maybeSetSequenceInfo(
|
| 131 |
+
const std::shared_ptr<ParamCommsDebugInfo>&,
|
| 132 |
+
const T&) {}
|
| 133 |
+
|
| 134 |
+
#define RECORD_PARAM_COMMS( \
|
| 135 |
+
seq, \
|
| 136 |
+
pgName, \
|
| 137 |
+
rank, \
|
| 138 |
+
collName, \
|
| 139 |
+
inNelems, \
|
| 140 |
+
outNelems, \
|
| 141 |
+
dType, \
|
| 142 |
+
inSplitSizes, \
|
| 143 |
+
outSplitSizes, \
|
| 144 |
+
globalRankStart, \
|
| 145 |
+
globalRankStride, \
|
| 146 |
+
worldSize) \
|
| 147 |
+
auto paramCommsInfo = std::make_shared<torch::ParamCommsDebugInfo>( \
|
| 148 |
+
pgName, \
|
| 149 |
+
rank, \
|
| 150 |
+
collName, \
|
| 151 |
+
inNelems, \
|
| 152 |
+
outNelems, \
|
| 153 |
+
dType, \
|
| 154 |
+
inSplitSizes, \
|
| 155 |
+
outSplitSizes, \
|
| 156 |
+
globalRankStart, \
|
| 157 |
+
globalRankStride, \
|
| 158 |
+
worldSize, \
|
| 159 |
+
false); \
|
| 160 |
+
torch::maybeSetSequenceInfo(paramCommsInfo, seq); \
|
| 161 |
+
c10::DebugInfoGuard g(c10::DebugInfoKind::PARAM_COMMS_INFO, paramCommsInfo); \
|
| 162 |
+
std::initializer_list<const c10::IValue> paramList = { \
|
| 163 |
+
seq, \
|
| 164 |
+
pgName, \
|
| 165 |
+
rank, \
|
| 166 |
+
collName, \
|
| 167 |
+
inSplitSizes, \
|
| 168 |
+
outSplitSizes, \
|
| 169 |
+
globalRankStart, \
|
| 170 |
+
globalRankStride, \
|
| 171 |
+
worldSize, \
|
| 172 |
+
false}; \
|
| 173 |
+
c10::ArrayRef<const c10::IValue> paramInputs(paramList); \
|
| 174 |
+
RECORD_FUNCTION(at::kParamCommsCallName, paramInputs);
|
| 175 |
+
|
| 176 |
+
#define RECORD_PARAM_COMMS_DATA( \
|
| 177 |
+
seq, \
|
| 178 |
+
pgName, \
|
| 179 |
+
InputTensors, \
|
| 180 |
+
OutputTensors, \
|
| 181 |
+
rank, \
|
| 182 |
+
collName, \
|
| 183 |
+
inNelems, \
|
| 184 |
+
outNelems, \
|
| 185 |
+
dType, \
|
| 186 |
+
inSplitSizes, \
|
| 187 |
+
outSplitSizes, \
|
| 188 |
+
globalRankStart, \
|
| 189 |
+
globalRankStride, \
|
| 190 |
+
worldSize) \
|
| 191 |
+
RECORD_PARAM_COMMS_DATA_WITH_ASYNC_OP( \
|
| 192 |
+
seq, \
|
| 193 |
+
pgName, \
|
| 194 |
+
InputTensors, \
|
| 195 |
+
OutputTensors, \
|
| 196 |
+
rank, \
|
| 197 |
+
collName, \
|
| 198 |
+
inNelems, \
|
| 199 |
+
outNelems, \
|
| 200 |
+
dType, \
|
| 201 |
+
inSplitSizes, \
|
| 202 |
+
outSplitSizes, \
|
| 203 |
+
globalRankStart, \
|
| 204 |
+
globalRankStride, \
|
| 205 |
+
worldSize, \
|
| 206 |
+
true);
|
| 207 |
+
|
| 208 |
+
#define RECORD_PARAM_COMMS_DATA_WITH_ASYNC_OP( \
|
| 209 |
+
seq, \
|
| 210 |
+
pgName, \
|
| 211 |
+
InputTensors, \
|
| 212 |
+
OutputTensors, \
|
| 213 |
+
rank, \
|
| 214 |
+
collName, \
|
| 215 |
+
inNelems, \
|
| 216 |
+
outNelems, \
|
| 217 |
+
dType, \
|
| 218 |
+
inSplitSizes, \
|
| 219 |
+
outSplitSizes, \
|
| 220 |
+
globalRankStart, \
|
| 221 |
+
globalRankStride, \
|
| 222 |
+
worldSize, \
|
| 223 |
+
isAsyncOp) \
|
| 224 |
+
auto paramCommsInfo = std::make_shared<torch::ParamCommsDebugInfo>( \
|
| 225 |
+
pgName, \
|
| 226 |
+
rank, \
|
| 227 |
+
collName, \
|
| 228 |
+
inNelems, \
|
| 229 |
+
outNelems, \
|
| 230 |
+
dType, \
|
| 231 |
+
inSplitSizes, \
|
| 232 |
+
outSplitSizes, \
|
| 233 |
+
globalRankStart, \
|
| 234 |
+
globalRankStride, \
|
| 235 |
+
worldSize, \
|
| 236 |
+
isAsyncOp); \
|
| 237 |
+
torch::maybeSetSequenceInfo(paramCommsInfo, seq); \
|
| 238 |
+
c10::DebugInfoGuard g(c10::DebugInfoKind::PARAM_COMMS_INFO, paramCommsInfo); \
|
| 239 |
+
std::initializer_list<const c10::IValue> paramList = { \
|
| 240 |
+
c10::IValue(InputTensors), \
|
| 241 |
+
seq, \
|
| 242 |
+
pgName, \
|
| 243 |
+
rank, \
|
| 244 |
+
collName, \
|
| 245 |
+
inSplitSizes, \
|
| 246 |
+
outSplitSizes, \
|
| 247 |
+
globalRankStart, \
|
| 248 |
+
globalRankStride, \
|
| 249 |
+
worldSize, \
|
| 250 |
+
isAsyncOp}; \
|
| 251 |
+
c10::ArrayRef<const c10::IValue> paramInputs(paramList); \
|
| 252 |
+
RECORD_FUNCTION_WITH_INPUTS_OUTPUTS( \
|
| 253 |
+
at::kParamCommsCallName, \
|
| 254 |
+
paramInputs, \
|
| 255 |
+
std::vector<c10::IValue>(1, c10::IValue(OutputTensors)));
|
| 256 |
+
} // namespace torch
|
| 257 |
+
|
| 258 |
+
#else
|
| 259 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 260 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/PrefixStore.hpp
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <torch/csrc/distributed/c10d/Store.hpp>
|
| 5 |
+
|
| 6 |
+
namespace c10d {
|
| 7 |
+
|
| 8 |
+
class TORCH_API PrefixStore : public Store {
|
| 9 |
+
public:
|
| 10 |
+
explicit PrefixStore(std::string prefix, c10::intrusive_ptr<Store> store);
|
| 11 |
+
|
| 12 |
+
c10::intrusive_ptr<Store> clone() override;
|
| 13 |
+
|
| 14 |
+
using Store::set;
|
| 15 |
+
void set(const std::string& key, const std::vector<uint8_t>& value) override;
|
| 16 |
+
|
| 17 |
+
using Store::compareSet;
|
| 18 |
+
std::vector<uint8_t> compareSet(
|
| 19 |
+
const std::string& key,
|
| 20 |
+
const std::vector<uint8_t>& expectedValue,
|
| 21 |
+
const std::vector<uint8_t>& desiredValue) override;
|
| 22 |
+
|
| 23 |
+
std::vector<uint8_t> get(const std::string& key) override;
|
| 24 |
+
|
| 25 |
+
int64_t add(const std::string& key, int64_t value) override;
|
| 26 |
+
|
| 27 |
+
bool deleteKey(const std::string& key) override;
|
| 28 |
+
|
| 29 |
+
int64_t getNumKeys() override;
|
| 30 |
+
|
| 31 |
+
bool check(const std::vector<std::string>& keys) override;
|
| 32 |
+
|
| 33 |
+
void wait(const std::vector<std::string>& keys) override;
|
| 34 |
+
|
| 35 |
+
void wait(
|
| 36 |
+
const std::vector<std::string>& keys,
|
| 37 |
+
const std::chrono::milliseconds& timeout) override;
|
| 38 |
+
|
| 39 |
+
const std::chrono::milliseconds& getTimeout() const noexcept override;
|
| 40 |
+
|
| 41 |
+
void setTimeout(const std::chrono::milliseconds& timeout) override;
|
| 42 |
+
|
| 43 |
+
void append(const std::string& key, const std::vector<uint8_t>& value)
|
| 44 |
+
override;
|
| 45 |
+
|
| 46 |
+
std::vector<std::vector<uint8_t>> multiGet(
|
| 47 |
+
const std::vector<std::string>& keys) override;
|
| 48 |
+
|
| 49 |
+
void multiSet(
|
| 50 |
+
const std::vector<std::string>& keys,
|
| 51 |
+
const std::vector<std::vector<uint8_t>>& values) override;
|
| 52 |
+
|
| 53 |
+
// Returns true if this store support append, multiGet and multiSet
|
| 54 |
+
bool hasExtendedApi() const override;
|
| 55 |
+
|
| 56 |
+
void queuePush(const std::string& key, const std::vector<uint8_t>& value)
|
| 57 |
+
override;
|
| 58 |
+
|
| 59 |
+
std::vector<uint8_t> queuePop(const std::string& key, bool block) override;
|
| 60 |
+
|
| 61 |
+
int64_t queueLen(const std::string& key) override;
|
| 62 |
+
|
| 63 |
+
c10::intrusive_ptr<Store> getUnderlyingStore();
|
| 64 |
+
|
| 65 |
+
// Recursively to fetch the store before layers of wrapping with PrefixStore.
|
| 66 |
+
c10::intrusive_ptr<Store> getUnderlyingNonPrefixStore();
|
| 67 |
+
|
| 68 |
+
std::vector<std::string> listKeys() override;
|
| 69 |
+
|
| 70 |
+
protected:
|
| 71 |
+
std::string prefix_;
|
| 72 |
+
c10::intrusive_ptr<Store> store_;
|
| 73 |
+
|
| 74 |
+
std::string joinKey(const std::string& key);
|
| 75 |
+
std::vector<std::string> joinKeys(const std::vector<std::string>& keys);
|
| 76 |
+
};
|
| 77 |
+
|
| 78 |
+
} // namespace c10d
|
| 79 |
+
|
| 80 |
+
#else
|
| 81 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 82 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroup.hpp
ADDED
|
@@ -0,0 +1,1037 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <torch/csrc/distributed/c10d/Backend.hpp>
|
| 5 |
+
#include <torch/csrc/distributed/c10d/Work.hpp>
|
| 6 |
+
#include <memory>
|
| 7 |
+
#include <unordered_map>
|
| 8 |
+
#include <utility>
|
| 9 |
+
#include <vector>
|
| 10 |
+
|
| 11 |
+
#include <ATen/ATen.h>
|
| 12 |
+
#include <ATen/core/dispatch/Dispatcher.h>
|
| 13 |
+
#include <c10/macros/Macros.h>
|
| 14 |
+
|
| 15 |
+
// *************************************************************************
|
| 16 |
+
// PROCESS GROUP collective communication API IS BEING CHANGED BETWEEN
|
| 17 |
+
// versions 1.7 and 1.8.
|
| 18 |
+
// PLEASE DO NOT ADD ANY DEPENDENCIES.
|
| 19 |
+
// SEE RFC: https://github.com/pytorch/pytorch/issues/39662
|
| 20 |
+
// *************************************************************************
|
| 21 |
+
|
| 22 |
+
constexpr auto kProcessGroupDefaultTimeout =
|
| 23 |
+
std::chrono::milliseconds(30 * 60 * 1000);
|
| 24 |
+
|
| 25 |
+
namespace c10d {
|
| 26 |
+
|
| 27 |
+
// We only call `register_work()` in two cases:
|
| 28 |
+
// 1. If the work object is created from a functional collective call.
|
| 29 |
+
// 2. If the work object is created from a non-functional collective call within
|
| 30 |
+
// the `with allow_inflight_collective_as_graph_input_ctx()` context manager.
|
| 31 |
+
C10_EXPORT void register_work(
|
| 32 |
+
const at::Tensor& tensor,
|
| 33 |
+
const c10::intrusive_ptr<c10d::Work>& work);
|
| 34 |
+
|
| 35 |
+
C10_EXPORT at::Tensor wait_tensor(const at::Tensor& tensor);
|
| 36 |
+
|
| 37 |
+
// We only call `unregister_work()` in one case:
|
| 38 |
+
// 1. If the work object is created from a non-functional collective call within
|
| 39 |
+
// the `with allow_inflight_collective_as_graph_input_ctx()` context manager.
|
| 40 |
+
//
|
| 41 |
+
// Q: What about the functional collective case?
|
| 42 |
+
// A: The unregistration of work object for functional collective is done in
|
| 43 |
+
// the required user-side explicit call to `wait_tensor()`.
|
| 44 |
+
C10_EXPORT void unregister_work(const c10::intrusive_ptr<c10d::Work>& work);
|
| 45 |
+
|
| 46 |
+
C10_EXPORT size_t get_work_registry_size();
|
| 47 |
+
|
| 48 |
+
C10_EXPORT void set_allow_inflight_collective_as_graph_input(bool value);
|
| 49 |
+
|
| 50 |
+
C10_EXPORT bool allow_inflight_collective_as_graph_input();
|
| 51 |
+
|
| 52 |
+
// ProcessGroup is a base class that captures collective and point to
|
| 53 |
+
// point communication in a fixed set of processes.
|
| 54 |
+
//
|
| 55 |
+
// The functions specified in the class below describe the API alone;
|
| 56 |
+
// implementations are provided in subclasses.
|
| 57 |
+
//
|
| 58 |
+
// Every function that performs I/O is executed asynchronously by a
|
| 59 |
+
// thread pool owned by the ProcessGroup (by default). They return an
|
| 60 |
+
// object that can be used to wait for completion or error.
|
| 61 |
+
//
|
| 62 |
+
// The ProcessGroup can instantiate subgroups with fewer or an equal
|
| 63 |
+
// number of members. Implementations must take care that multiple
|
| 64 |
+
// process groups can be used in parallel and synchronize accordingly.
|
| 65 |
+
//
|
| 66 |
+
// The ProcessGroup assumes a fixed set of processes. If the set
|
| 67 |
+
// changes, existing instances must be destructed and instantiation
|
| 68 |
+
// and initialization must start from scratch. For members of the
|
| 69 |
+
// process group to find each other (referred to as rendezvous from
|
| 70 |
+
// hereon)
|
| 71 |
+
//
|
| 72 |
+
class TORCH_API ProcessGroup : public torch::CustomClassHolder {
|
| 73 |
+
public:
|
| 74 |
+
struct TORCH_API MergeOptions : torch::CustomClassHolder {
|
| 75 |
+
explicit MergeOptions(
|
| 76 |
+
const std::chrono::milliseconds timeout = kProcessGroupDefaultTimeout,
|
| 77 |
+
const std::optional<std::string> group_name = std::nullopt,
|
| 78 |
+
const std::optional<std::string> group_desc = std::nullopt)
|
| 79 |
+
: timeout(timeout), group_name(group_name), group_desc(group_desc) {}
|
| 80 |
+
~MergeOptions() override = default;
|
| 81 |
+
MergeOptions(const MergeOptions&) = delete;
|
| 82 |
+
MergeOptions& operator=(const MergeOptions&) = delete;
|
| 83 |
+
|
| 84 |
+
std::chrono::milliseconds timeout;
|
| 85 |
+
std::optional<std::string> group_name;
|
| 86 |
+
std::optional<std::string> group_desc;
|
| 87 |
+
};
|
| 88 |
+
|
| 89 |
+
enum BackendType : uint8_t {
|
| 90 |
+
UNDEFINED = 0,
|
| 91 |
+
GLOO = 1,
|
| 92 |
+
NCCL = 2,
|
| 93 |
+
UCC = 3,
|
| 94 |
+
MPI = 4,
|
| 95 |
+
XCCL = 5,
|
| 96 |
+
CUSTOM = 6,
|
| 97 |
+
};
|
| 98 |
+
|
| 99 |
+
static std::string backendTypeToString(const BackendType& type) {
|
| 100 |
+
switch (type) {
|
| 101 |
+
case BackendType::GLOO:
|
| 102 |
+
return "gloo";
|
| 103 |
+
case BackendType::NCCL:
|
| 104 |
+
return "nccl";
|
| 105 |
+
case BackendType::XCCL:
|
| 106 |
+
return "xccl";
|
| 107 |
+
case BackendType::UCC:
|
| 108 |
+
return "ucc";
|
| 109 |
+
case BackendType::MPI:
|
| 110 |
+
return "mpi";
|
| 111 |
+
case BackendType::UNDEFINED:
|
| 112 |
+
return "undefined";
|
| 113 |
+
case BackendType::CUSTOM:
|
| 114 |
+
return "custom";
|
| 115 |
+
default:
|
| 116 |
+
TORCH_CHECK(false, "THis should never happen!");
|
| 117 |
+
}
|
| 118 |
+
}
|
| 119 |
+
|
| 120 |
+
static BackendType strToBackendType(const std::string& backend) {
|
| 121 |
+
if (backend == "undefined") {
|
| 122 |
+
return BackendType::UNDEFINED;
|
| 123 |
+
} else if (backend == "gloo") {
|
| 124 |
+
return BackendType::GLOO;
|
| 125 |
+
} else if (backend == "nccl") {
|
| 126 |
+
return BackendType::NCCL;
|
| 127 |
+
} else if (backend == "xccl") {
|
| 128 |
+
return BackendType::XCCL;
|
| 129 |
+
} else if (backend == "ucc") {
|
| 130 |
+
return BackendType::UCC;
|
| 131 |
+
} else if (backend == "mpi") {
|
| 132 |
+
return BackendType::MPI;
|
| 133 |
+
} else {
|
| 134 |
+
return BackendType::CUSTOM;
|
| 135 |
+
}
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
// Not used, set for backwards compatibility and only used for TypeDef in
|
| 139 |
+
// Ops.cpp
|
| 140 |
+
explicit ProcessGroup(int rank, int size);
|
| 141 |
+
|
| 142 |
+
explicit ProcessGroup(
|
| 143 |
+
c10::intrusive_ptr<::c10d::Store> store,
|
| 144 |
+
int rank,
|
| 145 |
+
int size);
|
| 146 |
+
~ProcessGroup() override;
|
| 147 |
+
|
| 148 |
+
virtual int getRank() const {
|
| 149 |
+
return rank_;
|
| 150 |
+
}
|
| 151 |
+
|
| 152 |
+
virtual int getSize() const {
|
| 153 |
+
return size_;
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
// Returns an unique opaque ID of this process group object.
|
| 157 |
+
int64_t getID() const {
|
| 158 |
+
return reinterpret_cast<std::intptr_t>(this);
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
// Returns an unique opaque ID of a backend for the specific backend type
|
| 162 |
+
// that can correlate with this process group's collectives.
|
| 163 |
+
int64_t getBackendID(BackendType backend_type) const {
|
| 164 |
+
return reinterpret_cast<std::intptr_t>(getBackend(backend_type).get());
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
virtual const std::string getBackendName() const {
|
| 168 |
+
return backendTypeToString(backendType_);
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
BackendType getBackendType() const {
|
| 172 |
+
return backendType_;
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
inline bool backendSupportsSequenceNumbers(BackendType backendType) {
|
| 176 |
+
if (backendType == BackendType::GLOO || backendType == BackendType::NCCL ||
|
| 177 |
+
backendType == BackendType::XCCL || backendType == BackendType::UCC)
|
| 178 |
+
return true;
|
| 179 |
+
return false;
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
virtual void setTimeout(std::chrono::milliseconds timeout) {
|
| 183 |
+
for (auto& backend : backendTypeToBackend_) {
|
| 184 |
+
backend.second->setTimeout(timeout);
|
| 185 |
+
}
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
int64_t incrementSplitCount() {
|
| 189 |
+
return splitCounter_++;
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
virtual void startCoalescing(c10::DeviceType deviceType) {
|
| 193 |
+
// only nccl has implemented startCoalescing so only execute for nccl
|
| 194 |
+
// backends
|
| 195 |
+
auto backend = getBackend(deviceType);
|
| 196 |
+
backend->startCoalescing();
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
virtual c10::intrusive_ptr<Work> endCoalescing(c10::DeviceType deviceType) {
|
| 200 |
+
// only nccl has implemented endCoalescing so only execute for nccl
|
| 201 |
+
// backends
|
| 202 |
+
auto backend = getBackend(deviceType);
|
| 203 |
+
auto work = backend->endCoalescing();
|
| 204 |
+
return work;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
virtual c10::intrusive_ptr<Work> broadcast(
|
| 208 |
+
std::vector<at::Tensor>& tensors,
|
| 209 |
+
const BroadcastOptions& opts = BroadcastOptions()) {
|
| 210 |
+
static auto op =
|
| 211 |
+
c10::Dispatcher::singleton()
|
| 212 |
+
.findSchemaOrThrow("c10d::broadcast_", "")
|
| 213 |
+
.typed<
|
| 214 |
+
std::tuple<std::vector<at::Tensor>, c10::intrusive_ptr<Work>>(
|
| 215 |
+
at::TensorList,
|
| 216 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 217 |
+
int64_t,
|
| 218 |
+
int64_t,
|
| 219 |
+
bool,
|
| 220 |
+
int64_t)>();
|
| 221 |
+
// It's awakward to unbox the opts here and box them again in the custom C++
|
| 222 |
+
// op. But it's also complicated to make opts as a CustomClassHolder. Leave
|
| 223 |
+
// it as it is now.
|
| 224 |
+
auto work = std::get<1>(op.call(
|
| 225 |
+
tensors,
|
| 226 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 227 |
+
opts.rootRank,
|
| 228 |
+
opts.rootTensor,
|
| 229 |
+
opts.asyncOp,
|
| 230 |
+
opts.timeout.count()));
|
| 231 |
+
|
| 232 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 233 |
+
for (const auto& tensor : tensors) {
|
| 234 |
+
c10d::register_work(tensor, work);
|
| 235 |
+
}
|
| 236 |
+
}
|
| 237 |
+
return work;
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
virtual c10::intrusive_ptr<Work> allreduce(
|
| 241 |
+
std::vector<at::Tensor>& tensors,
|
| 242 |
+
const AllreduceOptions& opts = AllreduceOptions()) {
|
| 243 |
+
static auto op =
|
| 244 |
+
c10::Dispatcher::singleton()
|
| 245 |
+
.findSchemaOrThrow("c10d::allreduce_", "")
|
| 246 |
+
.typed<
|
| 247 |
+
std::tuple<std::vector<at::Tensor>, c10::intrusive_ptr<Work>>(
|
| 248 |
+
at::TensorList,
|
| 249 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 250 |
+
const c10::intrusive_ptr<::c10d::ReduceOp>&,
|
| 251 |
+
const std::optional<at::Tensor>& sparse_indices,
|
| 252 |
+
bool,
|
| 253 |
+
int64_t)>();
|
| 254 |
+
|
| 255 |
+
auto work = std::get<1>(op.call(
|
| 256 |
+
tensors,
|
| 257 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 258 |
+
c10::make_intrusive<ReduceOp>(opts.reduceOp),
|
| 259 |
+
opts.sparseIndices,
|
| 260 |
+
opts.asyncOp,
|
| 261 |
+
opts.timeout.count()));
|
| 262 |
+
|
| 263 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 264 |
+
for (const auto& tensor : tensors) {
|
| 265 |
+
c10d::register_work(tensor, work);
|
| 266 |
+
}
|
| 267 |
+
}
|
| 268 |
+
return work;
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
virtual c10::intrusive_ptr<Work> allreduce_coalesced(
|
| 272 |
+
std::vector<at::Tensor>& tensors,
|
| 273 |
+
const AllreduceCoalescedOptions& opts = AllreduceCoalescedOptions()) {
|
| 274 |
+
static auto op = c10::Dispatcher::singleton()
|
| 275 |
+
.findSchemaOrThrow("c10d::allreduce_coalesced_", "")
|
| 276 |
+
.typed<c10::intrusive_ptr<::c10d::Work>(
|
| 277 |
+
at::TensorList,
|
| 278 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 279 |
+
const c10::intrusive_ptr<::c10d::ReduceOp>&,
|
| 280 |
+
bool,
|
| 281 |
+
int64_t)>();
|
| 282 |
+
|
| 283 |
+
auto work = op.call(
|
| 284 |
+
tensors,
|
| 285 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 286 |
+
c10::make_intrusive<ReduceOp>(opts.reduceOp),
|
| 287 |
+
opts.asyncOp,
|
| 288 |
+
opts.timeout.count());
|
| 289 |
+
|
| 290 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 291 |
+
for (const auto& tensor : tensors) {
|
| 292 |
+
c10d::register_work(tensor, work);
|
| 293 |
+
}
|
| 294 |
+
}
|
| 295 |
+
return work;
|
| 296 |
+
}
|
| 297 |
+
|
| 298 |
+
virtual c10::intrusive_ptr<Work> reduce(
|
| 299 |
+
std::vector<at::Tensor>& tensors,
|
| 300 |
+
const ReduceOptions& opts = ReduceOptions()) {
|
| 301 |
+
static auto op = c10::Dispatcher::singleton()
|
| 302 |
+
.findSchemaOrThrow("c10d::reduce_", "")
|
| 303 |
+
.typed<c10::intrusive_ptr<::c10d::Work>(
|
| 304 |
+
at::TensorList,
|
| 305 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 306 |
+
const c10::intrusive_ptr<::c10d::ReduceOp>&,
|
| 307 |
+
int64_t,
|
| 308 |
+
int64_t,
|
| 309 |
+
bool,
|
| 310 |
+
int64_t)>();
|
| 311 |
+
auto work = op.call(
|
| 312 |
+
tensors,
|
| 313 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 314 |
+
c10::make_intrusive<ReduceOp>(opts.reduceOp),
|
| 315 |
+
opts.rootRank,
|
| 316 |
+
opts.rootTensor,
|
| 317 |
+
opts.asyncOp,
|
| 318 |
+
opts.timeout.count());
|
| 319 |
+
|
| 320 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 321 |
+
for (const auto& tensor : tensors) {
|
| 322 |
+
c10d::register_work(tensor, work);
|
| 323 |
+
}
|
| 324 |
+
}
|
| 325 |
+
return work;
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
virtual c10::intrusive_ptr<Work> allgather(
|
| 329 |
+
std::vector<std::vector<at::Tensor>>& outputTensors,
|
| 330 |
+
std::vector<at::Tensor>& inputTensors,
|
| 331 |
+
const AllgatherOptions& opts = AllgatherOptions()) {
|
| 332 |
+
static auto op = c10::Dispatcher::singleton()
|
| 333 |
+
.findSchemaOrThrow("c10d::allgather_", "")
|
| 334 |
+
.typed<std::tuple<
|
| 335 |
+
std::vector<std::vector<at::Tensor>>,
|
| 336 |
+
c10::intrusive_ptr<Work>>(
|
| 337 |
+
const std::vector<std::vector<at::Tensor>>&,
|
| 338 |
+
at::TensorList,
|
| 339 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 340 |
+
bool,
|
| 341 |
+
int64_t)>();
|
| 342 |
+
|
| 343 |
+
auto work = std::get<1>(op.call(
|
| 344 |
+
outputTensors,
|
| 345 |
+
inputTensors,
|
| 346 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 347 |
+
opts.asyncOp,
|
| 348 |
+
opts.timeout.count()));
|
| 349 |
+
|
| 350 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 351 |
+
for (const auto& tensor_list : outputTensors) {
|
| 352 |
+
for (const auto& tensor : tensor_list) {
|
| 353 |
+
c10d::register_work(tensor, work);
|
| 354 |
+
}
|
| 355 |
+
}
|
| 356 |
+
}
|
| 357 |
+
return work;
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
// Gathers a single tensor inputBuffer into a single buffer outputBuffer that
|
| 361 |
+
// is interpreted as a contiguous collection of size inputBuffer * WORLD_SIZE.
|
| 362 |
+
// For implementers of ProcessGroup API and advanced users only.
|
| 363 |
+
// Note: this function will be deprecated in near future.
|
| 364 |
+
virtual c10::intrusive_ptr<Work> _allgather_base(
|
| 365 |
+
at::Tensor& outputBuffer,
|
| 366 |
+
at::Tensor& inputBuffer,
|
| 367 |
+
const AllgatherOptions& opts = AllgatherOptions()) {
|
| 368 |
+
static auto op =
|
| 369 |
+
c10::Dispatcher::singleton()
|
| 370 |
+
.findSchemaOrThrow("c10d::_allgather_base_", "")
|
| 371 |
+
.typed<std::tuple<at::Tensor, c10::intrusive_ptr<Work>>(
|
| 372 |
+
at::Tensor&,
|
| 373 |
+
at::Tensor&,
|
| 374 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 375 |
+
bool,
|
| 376 |
+
int64_t)>();
|
| 377 |
+
|
| 378 |
+
auto work = std::get<1>(op.call(
|
| 379 |
+
outputBuffer,
|
| 380 |
+
inputBuffer,
|
| 381 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 382 |
+
opts.asyncOp,
|
| 383 |
+
opts.timeout.count()));
|
| 384 |
+
|
| 385 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 386 |
+
c10d::register_work(outputBuffer, work);
|
| 387 |
+
}
|
| 388 |
+
return work;
|
| 389 |
+
}
|
| 390 |
+
|
| 391 |
+
// This function is deprecated and will be moved out of ProcessGroup to comms:
|
| 392 |
+
// * do not add dependencies on this function,
|
| 393 |
+
// * do not implement it in your ProcessGroup, implement _allgather_base
|
| 394 |
+
// instead.
|
| 395 |
+
virtual c10::intrusive_ptr<Work> allgather_coalesced(
|
| 396 |
+
std::vector<std::vector<at::Tensor>>& outputTensorLists,
|
| 397 |
+
std::vector<at::Tensor>& inputTensors,
|
| 398 |
+
const AllgatherOptions& opts = AllgatherOptions()) {
|
| 399 |
+
static auto op = c10::Dispatcher::singleton()
|
| 400 |
+
.findSchemaOrThrow("c10d::allgather_coalesced_", "")
|
| 401 |
+
.typed<c10::intrusive_ptr<Work>(
|
| 402 |
+
const std::vector<std::vector<at::Tensor>>&,
|
| 403 |
+
const at::TensorList&,
|
| 404 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 405 |
+
bool)>();
|
| 406 |
+
|
| 407 |
+
auto work = op.call(
|
| 408 |
+
outputTensorLists,
|
| 409 |
+
inputTensors,
|
| 410 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 411 |
+
opts.asyncOp);
|
| 412 |
+
|
| 413 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 414 |
+
for (const auto& tensor_list : outputTensorLists) {
|
| 415 |
+
for (const auto& tensor : tensor_list) {
|
| 416 |
+
c10d::register_work(tensor, work);
|
| 417 |
+
}
|
| 418 |
+
}
|
| 419 |
+
}
|
| 420 |
+
return work;
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
+
// This function is a coalesced version of `allgather_into_tensor` (currently
|
| 424 |
+
// still named as `_allgather_base`). Each tensor in the vector corresponds to
|
| 425 |
+
// an input/output of one `allgather_into_tensor` operation.
|
| 426 |
+
virtual c10::intrusive_ptr<Work> allgather_into_tensor_coalesced(
|
| 427 |
+
std::vector<at::Tensor>& outputTensors,
|
| 428 |
+
std::vector<at::Tensor>& inputTensors,
|
| 429 |
+
const AllgatherOptions& opts = AllgatherOptions()) {
|
| 430 |
+
static auto op =
|
| 431 |
+
c10::Dispatcher::singleton()
|
| 432 |
+
.findSchemaOrThrow("c10d::allgather_into_tensor_coalesced_", "")
|
| 433 |
+
.typed<c10::intrusive_ptr<Work>(
|
| 434 |
+
const at::TensorList,
|
| 435 |
+
const at::TensorList,
|
| 436 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 437 |
+
bool)>();
|
| 438 |
+
|
| 439 |
+
auto work = op.call(
|
| 440 |
+
outputTensors,
|
| 441 |
+
inputTensors,
|
| 442 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 443 |
+
opts.asyncOp);
|
| 444 |
+
|
| 445 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 446 |
+
for (const auto& tensor : outputTensors) {
|
| 447 |
+
c10d::register_work(tensor, work);
|
| 448 |
+
}
|
| 449 |
+
}
|
| 450 |
+
return work;
|
| 451 |
+
}
|
| 452 |
+
|
| 453 |
+
virtual c10::intrusive_ptr<Work> gather(
|
| 454 |
+
std::vector<std::vector<at::Tensor>>& outputTensors,
|
| 455 |
+
std::vector<at::Tensor>& inputTensors,
|
| 456 |
+
const GatherOptions& opts = GatherOptions()) {
|
| 457 |
+
static auto op = c10::Dispatcher::singleton()
|
| 458 |
+
.findSchemaOrThrow("c10d::gather_", "")
|
| 459 |
+
.typed<c10::intrusive_ptr<::c10d::Work>(
|
| 460 |
+
const std::vector<std::vector<at::Tensor>>&,
|
| 461 |
+
const at::TensorList&,
|
| 462 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 463 |
+
int64_t,
|
| 464 |
+
bool,
|
| 465 |
+
int64_t)>();
|
| 466 |
+
auto work = op.call(
|
| 467 |
+
outputTensors,
|
| 468 |
+
inputTensors,
|
| 469 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 470 |
+
opts.rootRank,
|
| 471 |
+
opts.asyncOp,
|
| 472 |
+
opts.timeout.count());
|
| 473 |
+
|
| 474 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 475 |
+
for (const auto& tensor_list : outputTensors) {
|
| 476 |
+
for (const auto& tensor : tensor_list) {
|
| 477 |
+
c10d::register_work(tensor, work);
|
| 478 |
+
}
|
| 479 |
+
}
|
| 480 |
+
}
|
| 481 |
+
return work;
|
| 482 |
+
}
|
| 483 |
+
|
| 484 |
+
virtual c10::intrusive_ptr<Work> scatter(
|
| 485 |
+
std::vector<at::Tensor>& outputTensors,
|
| 486 |
+
std::vector<std::vector<at::Tensor>>& inputTensors,
|
| 487 |
+
const ScatterOptions& opts = ScatterOptions()) {
|
| 488 |
+
static auto op =
|
| 489 |
+
c10::Dispatcher::singleton()
|
| 490 |
+
.findSchemaOrThrow("c10d::scatter_", "")
|
| 491 |
+
.typed<
|
| 492 |
+
std::tuple<std::vector<at::Tensor>, c10::intrusive_ptr<Work>>(
|
| 493 |
+
const at::TensorList&,
|
| 494 |
+
const std::vector<std::vector<at::Tensor>>&,
|
| 495 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 496 |
+
int64_t,
|
| 497 |
+
bool,
|
| 498 |
+
int64_t)>();
|
| 499 |
+
auto work = std::get<1>(op.call(
|
| 500 |
+
outputTensors,
|
| 501 |
+
inputTensors,
|
| 502 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 503 |
+
opts.rootRank,
|
| 504 |
+
opts.asyncOp,
|
| 505 |
+
opts.timeout.count()));
|
| 506 |
+
|
| 507 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 508 |
+
for (const auto& tensor : outputTensors) {
|
| 509 |
+
c10d::register_work(tensor, work);
|
| 510 |
+
}
|
| 511 |
+
}
|
| 512 |
+
return work;
|
| 513 |
+
}
|
| 514 |
+
|
| 515 |
+
virtual c10::intrusive_ptr<Work> reduce_scatter(
|
| 516 |
+
std::vector<at::Tensor>& outputTensors,
|
| 517 |
+
std::vector<std::vector<at::Tensor>>& inputTensors,
|
| 518 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) {
|
| 519 |
+
static auto op =
|
| 520 |
+
c10::Dispatcher::singleton()
|
| 521 |
+
.findSchemaOrThrow("c10d::reduce_scatter_", "")
|
| 522 |
+
.typed<
|
| 523 |
+
std::tuple<std::vector<at::Tensor>, c10::intrusive_ptr<Work>>(
|
| 524 |
+
const at::TensorList&,
|
| 525 |
+
const std::vector<std::vector<at::Tensor>>&,
|
| 526 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 527 |
+
const c10::intrusive_ptr<::c10d::ReduceOp>&,
|
| 528 |
+
bool,
|
| 529 |
+
int64_t)>();
|
| 530 |
+
auto work = std::get<1>(op.call(
|
| 531 |
+
outputTensors,
|
| 532 |
+
inputTensors,
|
| 533 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 534 |
+
c10::make_intrusive<::c10d::ReduceOp>(opts.reduceOp),
|
| 535 |
+
opts.asyncOp,
|
| 536 |
+
opts.timeout.count()));
|
| 537 |
+
|
| 538 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 539 |
+
for (const auto& tensor : outputTensors) {
|
| 540 |
+
c10d::register_work(tensor, work);
|
| 541 |
+
}
|
| 542 |
+
}
|
| 543 |
+
return work;
|
| 544 |
+
}
|
| 545 |
+
|
| 546 |
+
virtual c10::intrusive_ptr<Work> _reduce_scatter_base(
|
| 547 |
+
at::Tensor& outputBuffer,
|
| 548 |
+
at::Tensor& inputBuffer,
|
| 549 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) {
|
| 550 |
+
static auto op =
|
| 551 |
+
c10::Dispatcher::singleton()
|
| 552 |
+
.findSchemaOrThrow("c10d::_reduce_scatter_base_", "")
|
| 553 |
+
.typed<std::tuple<at::Tensor, c10::intrusive_ptr<Work>>(
|
| 554 |
+
at::Tensor&,
|
| 555 |
+
at::Tensor&,
|
| 556 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 557 |
+
const c10::intrusive_ptr<::c10d::ReduceOp>&,
|
| 558 |
+
bool,
|
| 559 |
+
int64_t)>();
|
| 560 |
+
auto work = std::get<1>(op.call(
|
| 561 |
+
outputBuffer,
|
| 562 |
+
inputBuffer,
|
| 563 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 564 |
+
c10::make_intrusive<::c10d::ReduceOp>(opts.reduceOp),
|
| 565 |
+
opts.asyncOp,
|
| 566 |
+
opts.timeout.count()));
|
| 567 |
+
|
| 568 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 569 |
+
c10d::register_work(outputBuffer, work);
|
| 570 |
+
}
|
| 571 |
+
return work;
|
| 572 |
+
}
|
| 573 |
+
|
| 574 |
+
// This function is a coalesced version of `reduce_scatter_tensor` (currently
|
| 575 |
+
// still named as `_reduce_scatter_base`). Each tensor in the vector
|
| 576 |
+
// corresponds to an input/output of one `reduce_scatter_tensor` operation.
|
| 577 |
+
virtual c10::intrusive_ptr<Work> reduce_scatter_tensor_coalesced(
|
| 578 |
+
std::vector<at::Tensor>& outputTensors,
|
| 579 |
+
std::vector<at::Tensor>& inputTensors,
|
| 580 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) {
|
| 581 |
+
static auto op =
|
| 582 |
+
c10::Dispatcher::singleton()
|
| 583 |
+
.findSchemaOrThrow("c10d::reduce_scatter_tensor_coalesced_", "")
|
| 584 |
+
.typed<c10::intrusive_ptr<Work>(
|
| 585 |
+
const at::TensorList,
|
| 586 |
+
const at::TensorList,
|
| 587 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 588 |
+
const c10::intrusive_ptr<::c10d::ReduceOp>&,
|
| 589 |
+
bool,
|
| 590 |
+
int64_t)>();
|
| 591 |
+
|
| 592 |
+
auto work = op.call(
|
| 593 |
+
outputTensors,
|
| 594 |
+
inputTensors,
|
| 595 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 596 |
+
c10::make_intrusive<::c10d::ReduceOp>(opts.reduceOp),
|
| 597 |
+
opts.asyncOp,
|
| 598 |
+
opts.timeout.count());
|
| 599 |
+
|
| 600 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 601 |
+
for (const auto& tensor : outputTensors) {
|
| 602 |
+
c10d::register_work(tensor, work);
|
| 603 |
+
}
|
| 604 |
+
}
|
| 605 |
+
return work;
|
| 606 |
+
}
|
| 607 |
+
|
| 608 |
+
virtual c10::intrusive_ptr<Work> alltoall_base(
|
| 609 |
+
at::Tensor& outputBuffer,
|
| 610 |
+
at::Tensor& inputBuffer,
|
| 611 |
+
std::vector<int64_t>& outputSplitSizes,
|
| 612 |
+
std::vector<int64_t>& inputSplitSizes,
|
| 613 |
+
const AllToAllOptions& opts = AllToAllOptions()) {
|
| 614 |
+
static auto op = c10::Dispatcher::singleton()
|
| 615 |
+
.findSchemaOrThrow("c10d::alltoall_base_", "")
|
| 616 |
+
.typed<c10::intrusive_ptr<::c10d::Work>(
|
| 617 |
+
at::Tensor&,
|
| 618 |
+
at::Tensor&,
|
| 619 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 620 |
+
std::vector<int64_t>,
|
| 621 |
+
std::vector<int64_t>,
|
| 622 |
+
bool,
|
| 623 |
+
int64_t)>();
|
| 624 |
+
auto work = op.call(
|
| 625 |
+
outputBuffer,
|
| 626 |
+
inputBuffer,
|
| 627 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 628 |
+
outputSplitSizes,
|
| 629 |
+
inputSplitSizes,
|
| 630 |
+
opts.asyncOp,
|
| 631 |
+
opts.timeout.count());
|
| 632 |
+
|
| 633 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 634 |
+
c10d::register_work(outputBuffer, work);
|
| 635 |
+
}
|
| 636 |
+
return work;
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
virtual c10::intrusive_ptr<Work> alltoall(
|
| 640 |
+
std::vector<at::Tensor>& outputTensors,
|
| 641 |
+
std::vector<at::Tensor>& inputTensors,
|
| 642 |
+
const AllToAllOptions& opts = AllToAllOptions()) {
|
| 643 |
+
static auto op =
|
| 644 |
+
c10::Dispatcher::singleton()
|
| 645 |
+
.findSchemaOrThrow("c10d::alltoall_", "")
|
| 646 |
+
.typed<
|
| 647 |
+
std::tuple<std::vector<at::Tensor>, c10::intrusive_ptr<Work>>(
|
| 648 |
+
const at::TensorList&,
|
| 649 |
+
const at::TensorList&,
|
| 650 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 651 |
+
bool,
|
| 652 |
+
int64_t)>();
|
| 653 |
+
auto work = std::get<1>(op.call(
|
| 654 |
+
outputTensors,
|
| 655 |
+
inputTensors,
|
| 656 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 657 |
+
opts.asyncOp,
|
| 658 |
+
opts.timeout.count()));
|
| 659 |
+
|
| 660 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 661 |
+
for (const auto& tensor : outputTensors) {
|
| 662 |
+
c10d::register_work(tensor, work);
|
| 663 |
+
}
|
| 664 |
+
}
|
| 665 |
+
return work;
|
| 666 |
+
}
|
| 667 |
+
|
| 668 |
+
virtual void monitoredBarrier(
|
| 669 |
+
const BarrierOptions& opts,
|
| 670 |
+
bool wait_all_ranks = false) {
|
| 671 |
+
static auto op = c10::Dispatcher::singleton()
|
| 672 |
+
.findSchemaOrThrow("c10d::monitored_barrier_", "")
|
| 673 |
+
.typed<void(
|
| 674 |
+
at::Tensor,
|
| 675 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 676 |
+
const std::vector<int64_t>&,
|
| 677 |
+
int64_t,
|
| 678 |
+
bool)>();
|
| 679 |
+
// Default to using cpu implementation, monitored barrier is only for GLOO
|
| 680 |
+
at::Tensor tensor = at::empty({0}, at::TensorOptions().device(at::kCPU));
|
| 681 |
+
op.call(
|
| 682 |
+
tensor,
|
| 683 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 684 |
+
opts.device_ids,
|
| 685 |
+
opts.timeout.count(),
|
| 686 |
+
wait_all_ranks);
|
| 687 |
+
}
|
| 688 |
+
|
| 689 |
+
// Agrees on an initial sequence number for the whole group by having rank 0
|
| 690 |
+
// create it and broadcast it to other ranks using the store. Only implemented
|
| 691 |
+
// for GLOO and NCCL backends currently.
|
| 692 |
+
virtual void setSequenceNumberForGroup() {
|
| 693 |
+
auto backendType = getBackendType();
|
| 694 |
+
// TODO: HACK for backend name to get sequence number for that backend.
|
| 695 |
+
if (backendSupportsSequenceNumbers(backendType)) {
|
| 696 |
+
getDefaultBackend()->setSequenceNumberForGroup();
|
| 697 |
+
} else {
|
| 698 |
+
TORCH_CHECK(
|
| 699 |
+
false,
|
| 700 |
+
c10::str(
|
| 701 |
+
"ProcessGroup ",
|
| 702 |
+
getBackendName(),
|
| 703 |
+
" does not yet support sequence numbers."));
|
| 704 |
+
}
|
| 705 |
+
}
|
| 706 |
+
|
| 707 |
+
// Retrieves the current sequence number for the whole group, which should be
|
| 708 |
+
// in sync. If the returned number is not consistent across the group, it
|
| 709 |
+
// may indicate that there is some sort of collective desynchronization.
|
| 710 |
+
virtual uint64_t getSequenceNumberForGroup() {
|
| 711 |
+
auto backendType = getBackendType();
|
| 712 |
+
|
| 713 |
+
// TODO: HACK for backend name to get sequence number for that backend.
|
| 714 |
+
if (backendSupportsSequenceNumbers(backendType)) {
|
| 715 |
+
return getDefaultBackend()->getSequenceNumberForGroup();
|
| 716 |
+
} else {
|
| 717 |
+
TORCH_CHECK(
|
| 718 |
+
false,
|
| 719 |
+
c10::str(
|
| 720 |
+
"ProcessGroup ",
|
| 721 |
+
getBackendName(),
|
| 722 |
+
" does not yet support sequence numbers."));
|
| 723 |
+
}
|
| 724 |
+
}
|
| 725 |
+
|
| 726 |
+
virtual c10::intrusive_ptr<Work> send(
|
| 727 |
+
std::vector<at::Tensor>& tensors,
|
| 728 |
+
int dstRank,
|
| 729 |
+
int tag) {
|
| 730 |
+
static auto op = c10::Dispatcher::singleton()
|
| 731 |
+
.findSchemaOrThrow("c10d::send", "")
|
| 732 |
+
.typed<c10::intrusive_ptr<::c10d::Work>(
|
| 733 |
+
at::TensorList,
|
| 734 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 735 |
+
int64_t,
|
| 736 |
+
int64_t)>();
|
| 737 |
+
auto work = op.call(
|
| 738 |
+
tensors,
|
| 739 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 740 |
+
dstRank,
|
| 741 |
+
tag);
|
| 742 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 743 |
+
for (const auto& tensor : tensors) {
|
| 744 |
+
c10d::register_work(tensor, work);
|
| 745 |
+
}
|
| 746 |
+
}
|
| 747 |
+
return work;
|
| 748 |
+
}
|
| 749 |
+
|
| 750 |
+
virtual c10::intrusive_ptr<Work> recv(
|
| 751 |
+
std::vector<at::Tensor>& tensors,
|
| 752 |
+
int srcRank,
|
| 753 |
+
int tag) {
|
| 754 |
+
static auto op = c10::Dispatcher::singleton()
|
| 755 |
+
.findSchemaOrThrow("c10d::recv_", "")
|
| 756 |
+
.typed<c10::intrusive_ptr<::c10d::Work>(
|
| 757 |
+
at::TensorList,
|
| 758 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 759 |
+
int64_t,
|
| 760 |
+
int64_t)>();
|
| 761 |
+
auto work = op.call(
|
| 762 |
+
tensors,
|
| 763 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 764 |
+
srcRank,
|
| 765 |
+
tag);
|
| 766 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 767 |
+
for (const auto& tensor : tensors) {
|
| 768 |
+
c10d::register_work(tensor, work);
|
| 769 |
+
}
|
| 770 |
+
}
|
| 771 |
+
return work;
|
| 772 |
+
}
|
| 773 |
+
|
| 774 |
+
virtual c10::intrusive_ptr<Work> recvAnysource(
|
| 775 |
+
std::vector<at::Tensor>& tensors,
|
| 776 |
+
int tag) {
|
| 777 |
+
static auto op = c10::Dispatcher::singleton()
|
| 778 |
+
.findSchemaOrThrow("c10d::recv_any_source_", "")
|
| 779 |
+
.typed<c10::intrusive_ptr<::c10d::Work>(
|
| 780 |
+
at::TensorList,
|
| 781 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 782 |
+
int64_t)>();
|
| 783 |
+
auto work = op.call(
|
| 784 |
+
tensors,
|
| 785 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 786 |
+
tag);
|
| 787 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 788 |
+
for (const auto& tensor : tensors) {
|
| 789 |
+
c10d::register_work(tensor, work);
|
| 790 |
+
}
|
| 791 |
+
}
|
| 792 |
+
return work;
|
| 793 |
+
}
|
| 794 |
+
|
| 795 |
+
virtual c10::intrusive_ptr<Work> barrier(
|
| 796 |
+
const BarrierOptions& opts = BarrierOptions()) {
|
| 797 |
+
at::Tensor tensor;
|
| 798 |
+
// TODO: if nccl was specified then use it
|
| 799 |
+
auto device = opts.device;
|
| 800 |
+
if (device.has_value()) {
|
| 801 |
+
// set device tensor from argument
|
| 802 |
+
tensor = at::empty(
|
| 803 |
+
{1}, at::TensorOptions().device(device.value()).dtype(at::kByte));
|
| 804 |
+
} else if (backendType_ == c10d::ProcessGroup::BackendType::NCCL) {
|
| 805 |
+
// set cuda tensor
|
| 806 |
+
tensor = at::empty(
|
| 807 |
+
{1},
|
| 808 |
+
at::TensorOptions().device(at::DeviceType::CUDA).dtype(at::kByte));
|
| 809 |
+
} else if (backendType_ == c10d::ProcessGroup::BackendType::XCCL) {
|
| 810 |
+
// set xpu tensor for override cpu dispatch
|
| 811 |
+
tensor = at::empty(
|
| 812 |
+
{1},
|
| 813 |
+
at::TensorOptions().device(at::DeviceType::XPU).dtype(at::kByte));
|
| 814 |
+
} else {
|
| 815 |
+
// Default to using cpu implementation
|
| 816 |
+
tensor = at::empty(
|
| 817 |
+
{1},
|
| 818 |
+
at::TensorOptions().device(at::DeviceType::CPU).dtype(at::kByte));
|
| 819 |
+
}
|
| 820 |
+
|
| 821 |
+
static auto op = c10::Dispatcher::singleton()
|
| 822 |
+
.findSchemaOrThrow("c10d::barrier", "")
|
| 823 |
+
.typed<c10::intrusive_ptr<::c10d::Work>(
|
| 824 |
+
at::Tensor,
|
| 825 |
+
const c10::intrusive_ptr<::c10d::ProcessGroup>&,
|
| 826 |
+
const std::vector<int64_t>&,
|
| 827 |
+
bool,
|
| 828 |
+
int64_t)>();
|
| 829 |
+
|
| 830 |
+
auto work = op.call(
|
| 831 |
+
tensor,
|
| 832 |
+
c10::intrusive_ptr<ProcessGroup>::unsafe_reclaim_from_nonowning(this),
|
| 833 |
+
opts.device_ids,
|
| 834 |
+
opts.asyncOp,
|
| 835 |
+
opts.timeout.count());
|
| 836 |
+
if (c10d::allow_inflight_collective_as_graph_input()) {
|
| 837 |
+
c10d::register_work(tensor, work);
|
| 838 |
+
}
|
| 839 |
+
return work;
|
| 840 |
+
}
|
| 841 |
+
|
| 842 |
+
bool hasBackends() {
|
| 843 |
+
return !deviceTypeToBackendType_.empty();
|
| 844 |
+
}
|
| 845 |
+
|
| 846 |
+
void setBackend(
|
| 847 |
+
c10::DeviceType deviceType,
|
| 848 |
+
BackendType backendType,
|
| 849 |
+
const std::optional<c10::intrusive_ptr<Backend>>& backend) {
|
| 850 |
+
// TODO: should we add these entries after the backend setting succeeds?
|
| 851 |
+
deviceTypeToBackendType_[deviceType] = backendType;
|
| 852 |
+
deviceTypes_.insert(deviceType);
|
| 853 |
+
// if the backendType is already set then reuse it for this device
|
| 854 |
+
if (backendTypeToBackend_.find(backendType) !=
|
| 855 |
+
backendTypeToBackend_.end()) {
|
| 856 |
+
auto existingBackend = backendTypeToBackend_.at(backendType);
|
| 857 |
+
deviceTypeToBackend_[deviceType] = existingBackend;
|
| 858 |
+
TORCH_CHECK(
|
| 859 |
+
existingBackend->getBoundDeviceId() ==
|
| 860 |
+
(*backend)->getBoundDeviceId());
|
| 861 |
+
} else {
|
| 862 |
+
// check if backend has value
|
| 863 |
+
if (backend.has_value()) {
|
| 864 |
+
deviceTypeToBackend_[deviceType] = backend.value();
|
| 865 |
+
backendTypeToBackend_[backendType] = backend.value();
|
| 866 |
+
(*backend)->setBoundDeviceId(bound_device_id_);
|
| 867 |
+
}
|
| 868 |
+
}
|
| 869 |
+
}
|
| 870 |
+
|
| 871 |
+
c10::intrusive_ptr<Backend> getDefaultBackend() const {
|
| 872 |
+
auto backend_iter = backendTypeToBackend_.find(backendType_);
|
| 873 |
+
TORCH_CHECK(
|
| 874 |
+
backend_iter != backendTypeToBackend_.end(),
|
| 875 |
+
"Could not find the default backend type ",
|
| 876 |
+
uint16_t(backendType_),
|
| 877 |
+
" for Process Group with name ",
|
| 878 |
+
getBackendName(),
|
| 879 |
+
".");
|
| 880 |
+
return backend_iter->second;
|
| 881 |
+
}
|
| 882 |
+
|
| 883 |
+
void setDefaultBackend(const BackendType& backendType) {
|
| 884 |
+
backendType_ = backendType;
|
| 885 |
+
}
|
| 886 |
+
|
| 887 |
+
void setDefaultBackend(const std::string& backend) {
|
| 888 |
+
backendType_ = strToBackendType(backend);
|
| 889 |
+
}
|
| 890 |
+
|
| 891 |
+
c10::intrusive_ptr<Backend> getBackend(c10::DeviceType deviceType);
|
| 892 |
+
|
| 893 |
+
c10::intrusive_ptr<Backend> getBackend(BackendType backendType) const {
|
| 894 |
+
TORCH_CHECK(
|
| 895 |
+
backendTypeToBackend_.find(backendType) != backendTypeToBackend_.end(),
|
| 896 |
+
"Could not find backend type ",
|
| 897 |
+
uint16_t(backendType),
|
| 898 |
+
" for Process Group with name ",
|
| 899 |
+
backendTypeToString(backendType),
|
| 900 |
+
".");
|
| 901 |
+
return backendTypeToBackend_.at(backendType);
|
| 902 |
+
}
|
| 903 |
+
|
| 904 |
+
// Return device types supported by this ProcessGroup.
|
| 905 |
+
// Note: the return type is `Device` rather than `DeviceType` for the purpose
|
| 906 |
+
// of easy comparison at Python level. The `Device` will have default index
|
| 907 |
+
// (-1).
|
| 908 |
+
std::vector<c10::Device> getDeviceTypes() const {
|
| 909 |
+
std::vector<c10::Device> devices;
|
| 910 |
+
devices.reserve(deviceTypes_.size());
|
| 911 |
+
for (auto& dt : deviceTypes_) {
|
| 912 |
+
devices.emplace_back(dt);
|
| 913 |
+
}
|
| 914 |
+
return devices;
|
| 915 |
+
}
|
| 916 |
+
|
| 917 |
+
void registerOnCompletionHook(
|
| 918 |
+
std::function<void(std::shared_ptr<WorkInfo>)>&& hook) {
|
| 919 |
+
getDefaultBackend()->registerOnCompletionHook(std::move(hook));
|
| 920 |
+
}
|
| 921 |
+
|
| 922 |
+
void waitForPendingWorks() {
|
| 923 |
+
getDefaultBackend()->waitForPendingWorks();
|
| 924 |
+
}
|
| 925 |
+
|
| 926 |
+
virtual void shutdown() {
|
| 927 |
+
for (auto& backend : backendTypeToBackend_) {
|
| 928 |
+
backend.second->shutdown();
|
| 929 |
+
}
|
| 930 |
+
}
|
| 931 |
+
|
| 932 |
+
virtual void abort() {
|
| 933 |
+
for (auto& backend : backendTypeToBackend_) {
|
| 934 |
+
backend.second->abort();
|
| 935 |
+
}
|
| 936 |
+
}
|
| 937 |
+
|
| 938 |
+
bool hasHooks() const {
|
| 939 |
+
auto backend_iter = backendTypeToBackend_.find(backendType_);
|
| 940 |
+
if (backend_iter == backendTypeToBackend_.end()) {
|
| 941 |
+
TORCH_WARN(
|
| 942 |
+
"No backend of type ",
|
| 943 |
+
uint16_t(backendType_),
|
| 944 |
+
" found for Process Group with name ",
|
| 945 |
+
getBackendName(),
|
| 946 |
+
". Assuming no hooks are registered.");
|
| 947 |
+
return false;
|
| 948 |
+
}
|
| 949 |
+
|
| 950 |
+
return backend_iter->second->hasHooks();
|
| 951 |
+
}
|
| 952 |
+
|
| 953 |
+
virtual const std::string& getGroupName() const;
|
| 954 |
+
virtual void setGroupName(const std::string& name);
|
| 955 |
+
virtual const std::string& getGroupDesc() const;
|
| 956 |
+
virtual void setGroupDesc(const std::string& name);
|
| 957 |
+
void enableCollectivesTiming();
|
| 958 |
+
|
| 959 |
+
void release_resources() override;
|
| 960 |
+
|
| 961 |
+
// ProcessGroups optionally can be "bound" to a specific device.
|
| 962 |
+
// Currently this is only for nccl and allows for some opt-in
|
| 963 |
+
// optimizations such as automatic use of ncclCommSplit. The device
|
| 964 |
+
// is specified in `init_process_group` and eventually makes it
|
| 965 |
+
// here and then down into the actual backend instances.
|
| 966 |
+
std::optional<at::Device> getBoundDeviceId() const {
|
| 967 |
+
return bound_device_id_;
|
| 968 |
+
}
|
| 969 |
+
|
| 970 |
+
c10::intrusive_ptr<c10d::Store> getStore() const {
|
| 971 |
+
return store_;
|
| 972 |
+
}
|
| 973 |
+
|
| 974 |
+
void setBoundDeviceId(std::optional<at::Device> device) {
|
| 975 |
+
if (device) {
|
| 976 |
+
TORCH_CHECK(device->has_index(), "setBoundDeviceId must have an index");
|
| 977 |
+
}
|
| 978 |
+
bound_device_id_ = device;
|
| 979 |
+
}
|
| 980 |
+
|
| 981 |
+
// This creates a new subgroup using the specified ranks.
|
| 982 |
+
// The current rank must be included in the list of new_ranks.
|
| 983 |
+
virtual c10::intrusive_ptr<ProcessGroup> splitGroup(
|
| 984 |
+
const std::vector<int>& ranks,
|
| 985 |
+
const std::optional<std::chrono::milliseconds>& timeout,
|
| 986 |
+
const std::optional<c10::intrusive_ptr<Backend::Options>>& opts,
|
| 987 |
+
const std::optional<std::string>& name,
|
| 988 |
+
const std::optional<std::string>& groupDesc);
|
| 989 |
+
|
| 990 |
+
// This creates a new subgroup using the specified ranks.
|
| 991 |
+
// The current rank must be included in the list of new_ranks.
|
| 992 |
+
virtual c10::intrusive_ptr<ProcessGroup> mergeRemoteGroup(
|
| 993 |
+
const c10::intrusive_ptr<Store>& store,
|
| 994 |
+
const MergeOptions& opts,
|
| 995 |
+
const int& size);
|
| 996 |
+
|
| 997 |
+
protected:
|
| 998 |
+
// Implementations of this interface need to call this to setup
|
| 999 |
+
// appropriate logging etc.
|
| 1000 |
+
void init();
|
| 1001 |
+
|
| 1002 |
+
c10::intrusive_ptr<c10d::Store> store_;
|
| 1003 |
+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
| 1004 |
+
const int rank_;
|
| 1005 |
+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
| 1006 |
+
const int size_;
|
| 1007 |
+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
| 1008 |
+
BackendType backendType_;
|
| 1009 |
+
std::string pg_desc_;
|
| 1010 |
+
int64_t splitCounter_;
|
| 1011 |
+
|
| 1012 |
+
// Debug level setting. It is parsed once when ProcessGroup is constructed and
|
| 1013 |
+
// remains the same across use of this process group.
|
| 1014 |
+
DebugLevel dist_debug_level_{DebugLevel::Off};
|
| 1015 |
+
|
| 1016 |
+
// Backend classes for this ProcessGroup
|
| 1017 |
+
std::unordered_set<c10::DeviceType> deviceTypes_;
|
| 1018 |
+
// This mapping is ordered, as splitGroup must call split on the underlying
|
| 1019 |
+
// backends in a consistent order.
|
| 1020 |
+
std::map<c10::DeviceType, BackendType> deviceTypeToBackendType_;
|
| 1021 |
+
std::unordered_map<c10::DeviceType, c10::intrusive_ptr<Backend>>
|
| 1022 |
+
deviceTypeToBackend_;
|
| 1023 |
+
std::unordered_map<BackendType, c10::intrusive_ptr<Backend>>
|
| 1024 |
+
backendTypeToBackend_;
|
| 1025 |
+
|
| 1026 |
+
std::optional<at::Device> bound_device_id_;
|
| 1027 |
+
};
|
| 1028 |
+
|
| 1029 |
+
// Thread local functions for managing the currently active process group.
|
| 1030 |
+
TORCH_API c10::intrusive_ptr<ProcessGroup>& currentProcessGroup();
|
| 1031 |
+
TORCH_API void setProcessGroup(c10::intrusive_ptr<ProcessGroup> processGroup);
|
| 1032 |
+
|
| 1033 |
+
} // namespace c10d
|
| 1034 |
+
|
| 1035 |
+
#else
|
| 1036 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 1037 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupGloo.hpp
ADDED
|
@@ -0,0 +1,508 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#ifdef USE_C10D_GLOO
|
| 5 |
+
|
| 6 |
+
#include <condition_variable>
|
| 7 |
+
#include <deque>
|
| 8 |
+
#include <mutex>
|
| 9 |
+
#include <thread>
|
| 10 |
+
#include <utility>
|
| 11 |
+
#include <vector>
|
| 12 |
+
|
| 13 |
+
#include <gloo/algorithm.h>
|
| 14 |
+
#include <gloo/common/error.h>
|
| 15 |
+
#include <gloo/context.h>
|
| 16 |
+
#include <gloo/rendezvous/store.h>
|
| 17 |
+
#include <gloo/transport/device.h>
|
| 18 |
+
|
| 19 |
+
#include <c10/util/hash.h>
|
| 20 |
+
|
| 21 |
+
#include <torch/csrc/distributed/c10d/Backend.hpp>
|
| 22 |
+
#include <torch/csrc/distributed/c10d/Store.hpp>
|
| 23 |
+
#include <torch/csrc/distributed/c10d/Types.hpp>
|
| 24 |
+
#include <torch/csrc/distributed/c10d/Utils.hpp>
|
| 25 |
+
#include <torch/csrc/distributed/c10d/logger.hpp>
|
| 26 |
+
|
| 27 |
+
#include <ATen/ThreadLocalState.h>
|
| 28 |
+
|
| 29 |
+
namespace c10d {
|
| 30 |
+
|
| 31 |
+
constexpr const char* GLOO_BACKEND_NAME = "gloo";
|
| 32 |
+
|
| 33 |
+
// Control whether or not connections are established in a full mesh or lazily
|
| 34 |
+
// as needed.
|
| 35 |
+
static std::vector<std::string> TORCH_GLOO_LAZY_INIT = {"TORCH_GLOO_LAZY_INIT"};
|
| 36 |
+
|
| 37 |
+
// Returns default value for lazyInit.
|
| 38 |
+
bool TORCH_API getDefaultGlooLazyInit();
|
| 39 |
+
|
| 40 |
+
// ProcessGroupGloo implements Gloo bindings for c10d.
|
| 41 |
+
//
|
| 42 |
+
// All functions on this class are expected to be called in the same
|
| 43 |
+
// order across processes in the group. This is the only way that we
|
| 44 |
+
// can guarantee to match up the same calls across processes. For
|
| 45 |
+
// multi-threaded usage of process groups, you can consider using
|
| 46 |
+
// multiple process group instances.
|
| 47 |
+
//
|
| 48 |
+
class TORCH_API ProcessGroupGloo : public Backend {
|
| 49 |
+
public:
|
| 50 |
+
// AsyncWork is the Gloo specific superclass for asynchronous work items.
|
| 51 |
+
// We can split asynchronous work into 3 phases:
|
| 52 |
+
// 1) Sanity checks and prepare input (e.g. memcpy)
|
| 53 |
+
// 2) Run operation on background thread
|
| 54 |
+
// 3) Synchronize with completion on foreground thread
|
| 55 |
+
//
|
| 56 |
+
// There is state to be shared between these 3 phases and all of this state
|
| 57 |
+
// is captured in the AsyncWork class and its derivatives.
|
| 58 |
+
//
|
| 59 |
+
// Note: while we are porting operations to use new style collectives, there
|
| 60 |
+
// is a split between operations using the existing caching approach and
|
| 61 |
+
// operations using the new AsyncWork base class. Over time we will port
|
| 62 |
+
// all operations and perform needed cleanup.
|
| 63 |
+
//
|
| 64 |
+
// FIXME: This probably should be called WorkGloo since the work is executed
|
| 65 |
+
// in sync mode by a background thread.
|
| 66 |
+
class TORCH_API AsyncWork : public Work {
|
| 67 |
+
public:
|
| 68 |
+
explicit AsyncWork(
|
| 69 |
+
std::shared_ptr<gloo::Context> context,
|
| 70 |
+
std::vector<std::vector<at::Tensor>> outputTensors,
|
| 71 |
+
OpType opType,
|
| 72 |
+
uint64_t seq,
|
| 73 |
+
std::chrono::milliseconds timeout,
|
| 74 |
+
const char* profilingTitle = nullptr,
|
| 75 |
+
const std::optional<std::vector<at::Tensor>>& inputTensors =
|
| 76 |
+
std::nullopt);
|
| 77 |
+
|
| 78 |
+
~AsyncWork() override = default;
|
| 79 |
+
|
| 80 |
+
static void execute(const c10::intrusive_ptr<AsyncWork>& work);
|
| 81 |
+
|
| 82 |
+
virtual void run() = 0;
|
| 83 |
+
|
| 84 |
+
std::vector<at::Tensor> result() override;
|
| 85 |
+
|
| 86 |
+
c10::intrusive_ptr<c10::ivalue::Future> getFuture() override;
|
| 87 |
+
uint64_t getSequencenumber() const override;
|
| 88 |
+
std::chrono::milliseconds getTimeout() const;
|
| 89 |
+
virtual const std::vector<at::Tensor> getInputTensors() = 0;
|
| 90 |
+
virtual const std::vector<at::Tensor> getOutputTensors() = 0;
|
| 91 |
+
inline std::string getProfilerTitle() const {
|
| 92 |
+
return profilingTitle_;
|
| 93 |
+
}
|
| 94 |
+
inline at::ThreadLocalState getTLS() const {
|
| 95 |
+
return tls_;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
protected:
|
| 99 |
+
friend class ProcessGroupGloo;
|
| 100 |
+
// unique id used to tell the trace buffer that this
|
| 101 |
+
// work has completed
|
| 102 |
+
std::optional<uint64_t> trace_id_;
|
| 103 |
+
std::optional<uint64_t> trace_reset_epoch_;
|
| 104 |
+
std::shared_ptr<gloo::Context> context_;
|
| 105 |
+
const std::chrono::milliseconds timeout_;
|
| 106 |
+
|
| 107 |
+
private:
|
| 108 |
+
void finishWorkGloo();
|
| 109 |
+
void finishWorkGlooError(const std::exception_ptr& eptr);
|
| 110 |
+
inline void recordAsyncWorkProfilingInfo(
|
| 111 |
+
const char* profilingTitle,
|
| 112 |
+
const std::optional<std::vector<at::Tensor>>& inputTensors);
|
| 113 |
+
|
| 114 |
+
const std::vector<std::vector<at::Tensor>> outputTensors_;
|
| 115 |
+
c10::intrusive_ptr<at::ivalue::Future> future_;
|
| 116 |
+
std::function<void()> recordFunctionBeforeCallback_;
|
| 117 |
+
const uint64_t seq_;
|
| 118 |
+
std::string profilingTitle_;
|
| 119 |
+
at::ThreadLocalState tls_;
|
| 120 |
+
};
|
| 121 |
+
|
| 122 |
+
// Wrap c10d store as Gloo store
|
| 123 |
+
class TORCH_API GlooStore : public ::gloo::rendezvous::Store {
|
| 124 |
+
public:
|
| 125 |
+
GlooStore(c10::intrusive_ptr<::c10d::Store> store)
|
| 126 |
+
: store_(std::move(store)) {}
|
| 127 |
+
|
| 128 |
+
void setUint(const std::string& key, const std::vector<uint8_t>& value) {
|
| 129 |
+
store_->set(key, value);
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
void set(const std::string& key, const std::vector<char>& value) override {
|
| 133 |
+
std::vector<uint8_t> tmp(value.begin(), value.end());
|
| 134 |
+
store_->set(key, tmp);
|
| 135 |
+
}
|
| 136 |
+
|
| 137 |
+
std::vector<uint8_t> getUint(const std::string& key) {
|
| 138 |
+
auto value = store_->get(key);
|
| 139 |
+
return value;
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
std::vector<char> get(const std::string& key) override {
|
| 143 |
+
auto value = store_->get(key);
|
| 144 |
+
return std::vector<char>(value.begin(), value.end());
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
void wait(const std::vector<std::string>& keys) override {
|
| 148 |
+
store_->wait(keys, ::c10d::Store::kDefaultTimeout);
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
void wait(
|
| 152 |
+
const std::vector<std::string>& keys,
|
| 153 |
+
const std::chrono::milliseconds& timeout) override {
|
| 154 |
+
store_->wait(keys, timeout);
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
#ifdef GLOO_STORE_HAS_STORE_V2
|
| 158 |
+
bool has_v2_support() override {
|
| 159 |
+
return store_->hasExtendedApi();
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
std::vector<std::vector<char>> multi_get(
|
| 163 |
+
const std::vector<std::string>& keys) override {
|
| 164 |
+
std::vector<std::vector<char>> res;
|
| 165 |
+
for (auto& value : store_->multiGet(keys)) {
|
| 166 |
+
res.emplace_back(value.begin(), value.end());
|
| 167 |
+
}
|
| 168 |
+
return res;
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
void multi_set(
|
| 172 |
+
const std::vector<std::string>& keys,
|
| 173 |
+
const std::vector<std::vector<char>>& values) override {
|
| 174 |
+
std::vector<std::vector<uint8_t>> u_values;
|
| 175 |
+
u_values.reserve(values.size());
|
| 176 |
+
for (auto& value : values) {
|
| 177 |
+
u_values.emplace_back(value.begin(), value.end());
|
| 178 |
+
}
|
| 179 |
+
store_->multiSet(keys, u_values);
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
void append(const std::string& key, const std::vector<char>& value)
|
| 183 |
+
override {
|
| 184 |
+
std::vector<uint8_t> tmp(value.begin(), value.end());
|
| 185 |
+
return store_->append(key, tmp);
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
int64_t add(const std::string& key, int64_t value) override {
|
| 189 |
+
return store_->add(key, value);
|
| 190 |
+
}
|
| 191 |
+
#endif
|
| 192 |
+
|
| 193 |
+
const c10::intrusive_ptr<::c10d::Store>& _getStore() const {
|
| 194 |
+
return store_;
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
protected:
|
| 198 |
+
c10::intrusive_ptr<::c10d::Store> store_;
|
| 199 |
+
};
|
| 200 |
+
|
| 201 |
+
// For send and recv operations there is no need to pass them to the
|
| 202 |
+
// thread pool as they are entirely completed by the device thread.
|
| 203 |
+
// This work object is used to synchronize completion of the send or
|
| 204 |
+
// recv operation. It keeps a reference to the tensor it is
|
| 205 |
+
// operating on to prevent it from being deallocated while the
|
| 206 |
+
// operation is still in flight.
|
| 207 |
+
class TORCH_API SendWork : public Work {
|
| 208 |
+
public:
|
| 209 |
+
explicit SendWork(
|
| 210 |
+
at::Tensor& tensor,
|
| 211 |
+
std::unique_ptr<::gloo::transport::UnboundBuffer> buffer,
|
| 212 |
+
uint64_t seq);
|
| 213 |
+
|
| 214 |
+
bool wait(std::chrono::milliseconds timeout = kNoTimeout) override;
|
| 215 |
+
|
| 216 |
+
void abort() override;
|
| 217 |
+
|
| 218 |
+
uint64_t getSequencenumber() const override;
|
| 219 |
+
|
| 220 |
+
protected:
|
| 221 |
+
at::Tensor tensor_;
|
| 222 |
+
std::unique_ptr<::gloo::transport::UnboundBuffer> buffer_;
|
| 223 |
+
const uint64_t seq_;
|
| 224 |
+
};
|
| 225 |
+
|
| 226 |
+
class TORCH_API RecvWork : public Work {
|
| 227 |
+
public:
|
| 228 |
+
explicit RecvWork(
|
| 229 |
+
at::Tensor& tensor,
|
| 230 |
+
std::unique_ptr<::gloo::transport::UnboundBuffer> buffer,
|
| 231 |
+
OpType opType,
|
| 232 |
+
uint64_t seq,
|
| 233 |
+
const char* profilingTitle = nullptr);
|
| 234 |
+
|
| 235 |
+
int sourceRank() const override;
|
| 236 |
+
|
| 237 |
+
bool wait(std::chrono::milliseconds timeout = kNoTimeout) override;
|
| 238 |
+
|
| 239 |
+
void abort() override;
|
| 240 |
+
|
| 241 |
+
uint64_t getSequencenumber() const override;
|
| 242 |
+
|
| 243 |
+
protected:
|
| 244 |
+
at::Tensor tensor_;
|
| 245 |
+
std::unique_ptr<::gloo::transport::UnboundBuffer> buffer_;
|
| 246 |
+
int srcRank_{-1};
|
| 247 |
+
const uint64_t seq_;
|
| 248 |
+
};
|
| 249 |
+
|
| 250 |
+
struct TORCH_API Options : public Backend::Options {
|
| 251 |
+
explicit Options(
|
| 252 |
+
std::chrono::milliseconds timeout = kBackendDefaultTimeout);
|
| 253 |
+
|
| 254 |
+
// return intrusive_ptr of the object
|
| 255 |
+
static c10::intrusive_ptr<Options> create(
|
| 256 |
+
std::chrono::milliseconds timeout = kBackendDefaultTimeout) {
|
| 257 |
+
return c10::make_intrusive<Options>(timeout);
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
static c10::intrusive_ptr<Options> create_default(
|
| 261 |
+
std::chrono::milliseconds timeout = kBackendDefaultTimeout);
|
| 262 |
+
|
| 263 |
+
std::vector<std::shared_ptr<::gloo::transport::Device>> devices;
|
| 264 |
+
int threads{2};
|
| 265 |
+
};
|
| 266 |
+
|
| 267 |
+
const std::string getBackendName() const override {
|
| 268 |
+
return std::string(GLOO_BACKEND_NAME);
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
bool supportsSplitting() const override {
|
| 272 |
+
return true;
|
| 273 |
+
}
|
| 274 |
+
|
| 275 |
+
// Helper functions to create a new device object.
|
| 276 |
+
// They are static functions on this class to keep them logically
|
| 277 |
+
// separate from the rest of the code base (e.g. torch/csrc/distributed).
|
| 278 |
+
|
| 279 |
+
// Create new device instance for specific interface.
|
| 280 |
+
static std::shared_ptr<::gloo::transport::Device> createDeviceForInterface(
|
| 281 |
+
const std::string& interface,
|
| 282 |
+
bool lazyInit = false);
|
| 283 |
+
|
| 284 |
+
// Create new device instance for specific hostname or address.
|
| 285 |
+
static std::shared_ptr<::gloo::transport::Device> createDeviceForHostname(
|
| 286 |
+
const std::string& hostname,
|
| 287 |
+
bool lazyInit = false);
|
| 288 |
+
|
| 289 |
+
// Create new device instance.
|
| 290 |
+
// It tries to resolve this machine's hostname and bind to that address.
|
| 291 |
+
// If that fails (i.e. the hostname doesn't resolve to an address), it
|
| 292 |
+
// falls back to binding to the loopback address.
|
| 293 |
+
static std::shared_ptr<::gloo::transport::Device> createDefaultDevice(
|
| 294 |
+
bool lazyInit = false);
|
| 295 |
+
|
| 296 |
+
explicit ProcessGroupGloo(
|
| 297 |
+
const c10::intrusive_ptr<Store>& store,
|
| 298 |
+
int rank,
|
| 299 |
+
int size,
|
| 300 |
+
c10::intrusive_ptr<Options> options = Options::create());
|
| 301 |
+
|
| 302 |
+
~ProcessGroupGloo() override;
|
| 303 |
+
|
| 304 |
+
c10::intrusive_ptr<Options> getOptions() {
|
| 305 |
+
return options_;
|
| 306 |
+
}
|
| 307 |
+
|
| 308 |
+
void setTimeout(std::chrono::milliseconds timeout) override {
|
| 309 |
+
options_->timeout = timeout;
|
| 310 |
+
for (auto& context : contexts_) {
|
| 311 |
+
context->setTimeout(timeout);
|
| 312 |
+
}
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
c10::intrusive_ptr<Backend::Options> getBackendOptions() override {
|
| 316 |
+
return c10::static_intrusive_pointer_cast<Backend::Options>(options_);
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
c10::intrusive_ptr<Backend> split(
|
| 320 |
+
const c10::intrusive_ptr<Store>& store,
|
| 321 |
+
const std::vector<int>& ranks,
|
| 322 |
+
const c10::intrusive_ptr<Backend::Options>& opts) override;
|
| 323 |
+
|
| 324 |
+
c10::intrusive_ptr<Backend> merge(
|
| 325 |
+
const c10::intrusive_ptr<Store>& store,
|
| 326 |
+
const c10::intrusive_ptr<Backend::Options>& opts,
|
| 327 |
+
const int& rank,
|
| 328 |
+
const int& size) override;
|
| 329 |
+
|
| 330 |
+
const std::vector<uint64_t>& groupRanks() const;
|
| 331 |
+
|
| 332 |
+
c10::intrusive_ptr<Work> broadcast(
|
| 333 |
+
std::vector<at::Tensor>& tensors,
|
| 334 |
+
const BroadcastOptions& opts = BroadcastOptions()) override;
|
| 335 |
+
|
| 336 |
+
c10::intrusive_ptr<Work> allreduce(
|
| 337 |
+
std::vector<at::Tensor>& tensors,
|
| 338 |
+
const AllreduceOptions& opts = AllreduceOptions()) override;
|
| 339 |
+
|
| 340 |
+
c10::intrusive_ptr<Work> allreduce_sparse(
|
| 341 |
+
std::vector<at::Tensor>& tensors,
|
| 342 |
+
const AllreduceOptions& opts = AllreduceOptions()) override;
|
| 343 |
+
|
| 344 |
+
c10::intrusive_ptr<Work> allreduce_coalesced(
|
| 345 |
+
std::vector<at::Tensor>& tensors,
|
| 346 |
+
const AllreduceCoalescedOptions& opts =
|
| 347 |
+
AllreduceCoalescedOptions()) override;
|
| 348 |
+
|
| 349 |
+
c10::intrusive_ptr<Work> reduce(
|
| 350 |
+
std::vector<at::Tensor>& tensors,
|
| 351 |
+
const ReduceOptions& opts = ReduceOptions()) override;
|
| 352 |
+
|
| 353 |
+
c10::intrusive_ptr<Work> _reduce_scatter_base(
|
| 354 |
+
at::Tensor& outputTensor,
|
| 355 |
+
at::Tensor& inputTensor,
|
| 356 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override;
|
| 357 |
+
|
| 358 |
+
c10::intrusive_ptr<Work> _allgather_base(
|
| 359 |
+
at::Tensor& output_tensor,
|
| 360 |
+
at::Tensor& input_tensor,
|
| 361 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 362 |
+
|
| 363 |
+
c10::intrusive_ptr<Work> allgather(
|
| 364 |
+
std::vector<std::vector<at::Tensor>>& outputs,
|
| 365 |
+
std::vector<at::Tensor>& inputs,
|
| 366 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 367 |
+
|
| 368 |
+
c10::intrusive_ptr<Work> allgather_coalesced(
|
| 369 |
+
std::vector<std::vector<at::Tensor>>& output_lists,
|
| 370 |
+
std::vector<at::Tensor>& input_list,
|
| 371 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 372 |
+
|
| 373 |
+
c10::intrusive_ptr<Work> allgather_into_tensor_coalesced(
|
| 374 |
+
std::vector<at::Tensor>& outputs,
|
| 375 |
+
std::vector<at::Tensor>& inputs,
|
| 376 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 377 |
+
|
| 378 |
+
c10::intrusive_ptr<Work> gather(
|
| 379 |
+
std::vector<std::vector<at::Tensor>>& outputs,
|
| 380 |
+
std::vector<at::Tensor>& inputs,
|
| 381 |
+
const GatherOptions& opts = GatherOptions()) override;
|
| 382 |
+
|
| 383 |
+
c10::intrusive_ptr<Work> scatter(
|
| 384 |
+
std::vector<at::Tensor>& outputs,
|
| 385 |
+
std::vector<std::vector<at::Tensor>>& inputs,
|
| 386 |
+
const ScatterOptions& opts = ScatterOptions()) override;
|
| 387 |
+
|
| 388 |
+
c10::intrusive_ptr<Work> reduce_scatter(
|
| 389 |
+
std::vector<at::Tensor>& outputs,
|
| 390 |
+
std::vector<std::vector<at::Tensor>>& inputs,
|
| 391 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override;
|
| 392 |
+
|
| 393 |
+
c10::intrusive_ptr<Work> reduce_scatter_tensor_coalesced(
|
| 394 |
+
std::vector<at::Tensor>& outputTensors,
|
| 395 |
+
std::vector<at::Tensor>& inputTensors,
|
| 396 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override;
|
| 397 |
+
|
| 398 |
+
c10::intrusive_ptr<Work> alltoall_base(
|
| 399 |
+
at::Tensor& outputTensor,
|
| 400 |
+
at::Tensor& inputTensor,
|
| 401 |
+
std::vector<int64_t>& outputCounts,
|
| 402 |
+
std::vector<int64_t>& inputCounts,
|
| 403 |
+
const AllToAllOptions& opts = AllToAllOptions()) override;
|
| 404 |
+
|
| 405 |
+
c10::intrusive_ptr<Work> alltoall(
|
| 406 |
+
std::vector<at::Tensor>& outputTensors,
|
| 407 |
+
std::vector<at::Tensor>& inputTensors,
|
| 408 |
+
const AllToAllOptions& opts = AllToAllOptions()) override;
|
| 409 |
+
|
| 410 |
+
c10::intrusive_ptr<Work> send(
|
| 411 |
+
std::vector<at::Tensor>& tensors,
|
| 412 |
+
int dstRank,
|
| 413 |
+
int tag) override;
|
| 414 |
+
|
| 415 |
+
c10::intrusive_ptr<Work> recv(
|
| 416 |
+
std::vector<at::Tensor>& tensors,
|
| 417 |
+
int srcRank,
|
| 418 |
+
int tag) override;
|
| 419 |
+
|
| 420 |
+
c10::intrusive_ptr<Work> recvAnysource(
|
| 421 |
+
std::vector<at::Tensor>& tensors,
|
| 422 |
+
int tag) override;
|
| 423 |
+
|
| 424 |
+
c10::intrusive_ptr<Work> barrier(
|
| 425 |
+
const BarrierOptions& opts = BarrierOptions()) override;
|
| 426 |
+
|
| 427 |
+
void enableCollectivesTiming() override;
|
| 428 |
+
|
| 429 |
+
const std::shared_ptr<::gloo::rendezvous::Store>& _getStore() const {
|
| 430 |
+
return store_;
|
| 431 |
+
}
|
| 432 |
+
|
| 433 |
+
// Similar to barrier(), but blocks rank 0 until all other ranks have
|
| 434 |
+
// acknowledged that they are alive (through send/recv from rank 0). Rank 0
|
| 435 |
+
// is able to report all failed ranks if waitAllRanks = true, otherwise
|
| 436 |
+
// reports the first rank it detected as failed.
|
| 437 |
+
void monitoredBarrier(
|
| 438 |
+
const BarrierOptions& opts = BarrierOptions(),
|
| 439 |
+
bool waitAllRanks = false) override;
|
| 440 |
+
|
| 441 |
+
// Agrees on an initial sequence number for the whole group by having rank 0
|
| 442 |
+
// create it and broadcast it to other ranks using the store.
|
| 443 |
+
void setSequenceNumberForGroup() override;
|
| 444 |
+
|
| 445 |
+
// Retrieves the current sequence number for the whole group, which should be
|
| 446 |
+
// in sync. If the returned number is not consistent across the group, it
|
| 447 |
+
// may indicate that there is some sort of collective desynchronization.
|
| 448 |
+
uint64_t getSequenceNumberForGroup() override;
|
| 449 |
+
|
| 450 |
+
int getNumThreads() {
|
| 451 |
+
return options_->threads;
|
| 452 |
+
}
|
| 453 |
+
|
| 454 |
+
protected:
|
| 455 |
+
std::shared_ptr<::gloo::rendezvous::Store> store_;
|
| 456 |
+
const c10::intrusive_ptr<Options> options_;
|
| 457 |
+
|
| 458 |
+
// Every Gloo context represents a set of connections to its peers.
|
| 459 |
+
// In order to use more than one device (or allow for parallelism on
|
| 460 |
+
// a single device), you need multiple contexts.
|
| 461 |
+
std::vector<std::shared_ptr<::gloo::Context>> contexts_;
|
| 462 |
+
std::vector<std::thread> threads_;
|
| 463 |
+
bool stop_{false};
|
| 464 |
+
|
| 465 |
+
// Incremented for every collective we kick off.
|
| 466 |
+
// The value is used as tag for collective operations. Collectives are kicked
|
| 467 |
+
// off in identical order across processes. Therefore the tag can be used
|
| 468 |
+
// to match up operations during concurrent execution.
|
| 469 |
+
uint32_t collectiveCounter_{0};
|
| 470 |
+
|
| 471 |
+
// Returns next collective tag to use (uses collectiveCounter_).
|
| 472 |
+
uint32_t nextTag();
|
| 473 |
+
|
| 474 |
+
// Returns the context to use for the specified tag.
|
| 475 |
+
// With `nextTag` returning an increasing number, this should lead
|
| 476 |
+
// to contexts being used in a round-robin fashion.
|
| 477 |
+
std::shared_ptr<::gloo::Context> getContext(uint32_t tag);
|
| 478 |
+
|
| 479 |
+
// Entrypoint for worker threads.
|
| 480 |
+
void runLoop(int workerIndex);
|
| 481 |
+
|
| 482 |
+
// Queue work to run on worker thread.
|
| 483 |
+
void enqueue(c10::intrusive_ptr<AsyncWork> work);
|
| 484 |
+
|
| 485 |
+
// Keep both a queue of pending work, and a vector with in progress work.
|
| 486 |
+
// Both of these can only be mutated when holding the queue lock.
|
| 487 |
+
// We keep both around instead of just the queue, so we can grab a weak_ptr
|
| 488 |
+
// to all in progress and pending work when executing a barrier.
|
| 489 |
+
// When executing a barrier, we need to ensure that all prior work
|
| 490 |
+
// has completed before completing itself.
|
| 491 |
+
std::deque<c10::intrusive_ptr<AsyncWork>> workQueue_;
|
| 492 |
+
std::vector<c10::intrusive_ptr<AsyncWork>> workInProgress_;
|
| 493 |
+
std::mutex workMutex_;
|
| 494 |
+
std::condition_variable workProduceCV_;
|
| 495 |
+
std::condition_variable workConsumeCV_;
|
| 496 |
+
uint64_t seq_{0};
|
| 497 |
+
size_t local_id_;
|
| 498 |
+
std::shared_ptr<ProcessGroupStatus> pgStatus_ =
|
| 499 |
+
std::make_shared<ProcessGroupStatus>();
|
| 500 |
+
};
|
| 501 |
+
|
| 502 |
+
} // namespace c10d
|
| 503 |
+
|
| 504 |
+
#endif // USE_C10D_GLOO
|
| 505 |
+
|
| 506 |
+
#else
|
| 507 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 508 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupGlooDetail.hpp
ADDED
|
@@ -0,0 +1,679 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#ifdef USE_C10D_GLOO
|
| 5 |
+
|
| 6 |
+
#include <c10/util/Registry.h>
|
| 7 |
+
#include <torch/csrc/distributed/c10d/ProcessGroupGloo.hpp>
|
| 8 |
+
|
| 9 |
+
#include <gloo/allgather.h>
|
| 10 |
+
#include <gloo/allgatherv.h>
|
| 11 |
+
#include <gloo/allreduce.h>
|
| 12 |
+
#include <gloo/alltoall.h>
|
| 13 |
+
#include <gloo/alltoallv.h>
|
| 14 |
+
#include <gloo/barrier.h>
|
| 15 |
+
#include <gloo/broadcast.h>
|
| 16 |
+
#include <gloo/gather.h>
|
| 17 |
+
#include <gloo/reduce.h>
|
| 18 |
+
#include <gloo/scatter.h>
|
| 19 |
+
|
| 20 |
+
#ifdef _WIN32
|
| 21 |
+
#define GENERATE_ALL_TYPES(type, func, ...) \
|
| 22 |
+
switch (type) { \
|
| 23 |
+
case ::at::ScalarType::Float: \
|
| 24 |
+
func<float>(__VA_ARGS__); \
|
| 25 |
+
break; \
|
| 26 |
+
case ::at::ScalarType::Double: \
|
| 27 |
+
func<double>(__VA_ARGS__); \
|
| 28 |
+
break; \
|
| 29 |
+
case ::at::ScalarType::Half: \
|
| 30 |
+
func<c10::Half>(__VA_ARGS__); \
|
| 31 |
+
break; \
|
| 32 |
+
case ::at::ScalarType::BFloat16: \
|
| 33 |
+
func<c10::BFloat16>(__VA_ARGS__); \
|
| 34 |
+
break; \
|
| 35 |
+
case ::at::ScalarType::Char: \
|
| 36 |
+
func<int8_t>(__VA_ARGS__); \
|
| 37 |
+
break; \
|
| 38 |
+
case ::at::ScalarType::Byte: \
|
| 39 |
+
case ::at::ScalarType::Bool: \
|
| 40 |
+
func<uint8_t>(__VA_ARGS__); \
|
| 41 |
+
break; \
|
| 42 |
+
case ::at::ScalarType::Int: \
|
| 43 |
+
func<int32_t>(__VA_ARGS__); \
|
| 44 |
+
break; \
|
| 45 |
+
case ::at::ScalarType::Long: \
|
| 46 |
+
func<int64_t>(__VA_ARGS__); \
|
| 47 |
+
break; \
|
| 48 |
+
default: \
|
| 49 |
+
TORCH_CHECK(false, "Invalid scalar type"); \
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
#define HOST_NAME_MAX 256
|
| 53 |
+
#else
|
| 54 |
+
#define GENERATE_ALL_TYPES(type, func, args...) \
|
| 55 |
+
switch (type) { \
|
| 56 |
+
case ::at::ScalarType::Float: \
|
| 57 |
+
func<float>(args); \
|
| 58 |
+
break; \
|
| 59 |
+
case ::at::ScalarType::Double: \
|
| 60 |
+
func<double>(args); \
|
| 61 |
+
break; \
|
| 62 |
+
case ::at::ScalarType::Half: \
|
| 63 |
+
func<c10::Half>(args); \
|
| 64 |
+
break; \
|
| 65 |
+
case ::at::ScalarType::BFloat16: \
|
| 66 |
+
func<c10::BFloat16>(args); \
|
| 67 |
+
break; \
|
| 68 |
+
case ::at::ScalarType::Char: \
|
| 69 |
+
func<int8_t>(args); \
|
| 70 |
+
break; \
|
| 71 |
+
case ::at::ScalarType::Byte: \
|
| 72 |
+
case ::at::ScalarType::Bool: \
|
| 73 |
+
func<uint8_t>(args); \
|
| 74 |
+
break; \
|
| 75 |
+
case ::at::ScalarType::Int: \
|
| 76 |
+
func<int32_t>(args); \
|
| 77 |
+
break; \
|
| 78 |
+
case ::at::ScalarType::Long: \
|
| 79 |
+
func<int64_t>(args); \
|
| 80 |
+
break; \
|
| 81 |
+
default: \
|
| 82 |
+
TORCH_CHECK(false, "Invalid scalar type"); \
|
| 83 |
+
}
|
| 84 |
+
#endif
|
| 85 |
+
|
| 86 |
+
namespace c10d {
|
| 87 |
+
|
| 88 |
+
TORCH_DECLARE_TYPED_REGISTRY(
|
| 89 |
+
GlooAllreduceRegistry,
|
| 90 |
+
c10::DeviceType,
|
| 91 |
+
ProcessGroupGloo::AsyncWork,
|
| 92 |
+
c10::intrusive_ptr,
|
| 93 |
+
std::shared_ptr<gloo::Context>,
|
| 94 |
+
std::vector<at::Tensor>&,
|
| 95 |
+
ReduceOp,
|
| 96 |
+
uint32_t,
|
| 97 |
+
uint64_t,
|
| 98 |
+
std::chrono::milliseconds);
|
| 99 |
+
|
| 100 |
+
// This function initializes a vector of CUDA streams, one for every
|
| 101 |
+
// tensor in the input tensor vector, and ensures that these streams are
|
| 102 |
+
// synchronized with the current default streams. This is needed so
|
| 103 |
+
// that new work on the new streams is serialized w.r.t. all operations
|
| 104 |
+
// on the tensors.
|
| 105 |
+
TORCH_API void initializeStreamsEvents(
|
| 106 |
+
const std::vector<at::Tensor>& tensors,
|
| 107 |
+
std::vector<c10::Stream>& streams,
|
| 108 |
+
std::vector<c10::Event>& events);
|
| 109 |
+
|
| 110 |
+
// This function initializes a vector of CUDA streams, one per device,
|
| 111 |
+
// and ensures that these streams are synchronized with the current default
|
| 112 |
+
// streams. It is assumed that the tensors in the nested tensor vectors are
|
| 113 |
+
// on the same device.
|
| 114 |
+
TORCH_API void initializeStreamsEvents(
|
| 115 |
+
std::vector<std::vector<at::Tensor>>& tensors,
|
| 116 |
+
std::vector<c10::Stream>& streams,
|
| 117 |
+
std::vector<c10::Event>& events);
|
| 118 |
+
|
| 119 |
+
typedef void (*ReduceFunc)(void*, const void*, const void*, size_t);
|
| 120 |
+
|
| 121 |
+
template <typename T, std::enable_if_t<!std::is_integral_v<T>, int> = 0>
|
| 122 |
+
ReduceFunc toFunction(const ReduceOp& r) {
|
| 123 |
+
switch (r) {
|
| 124 |
+
case ReduceOp::SUM:
|
| 125 |
+
case ReduceOp::AVG:
|
| 126 |
+
return ReduceFunc(&::gloo::sum<T>);
|
| 127 |
+
case ReduceOp::PRODUCT:
|
| 128 |
+
return ReduceFunc(&::gloo::product<T>);
|
| 129 |
+
case ReduceOp::MIN:
|
| 130 |
+
return ReduceFunc(&::gloo::min<T>);
|
| 131 |
+
case ReduceOp::MAX:
|
| 132 |
+
return ReduceFunc(&::gloo::max<T>);
|
| 133 |
+
case ReduceOp::BAND:
|
| 134 |
+
TORCH_CHECK(false, "Cannot use ReduceOp.BAND with non-integral dtype");
|
| 135 |
+
break;
|
| 136 |
+
case ReduceOp::BOR:
|
| 137 |
+
TORCH_CHECK(false, "Cannot use ReduceOp.BOR with non-integral dtype");
|
| 138 |
+
break;
|
| 139 |
+
case ReduceOp::BXOR:
|
| 140 |
+
TORCH_CHECK(false, "Cannot use ReduceOp.BXOR with non-integral dtype");
|
| 141 |
+
break;
|
| 142 |
+
case ReduceOp::PREMUL_SUM:
|
| 143 |
+
TORCH_CHECK(false, "Cannot use ReduceOp.PREMUL_SUM with Gloo");
|
| 144 |
+
break;
|
| 145 |
+
case ReduceOp::UNUSED:
|
| 146 |
+
default:
|
| 147 |
+
break;
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
TORCH_CHECK(false, "Unhandled ReduceOp");
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
// Bitwise AND with SFINAE guard for integral types.
|
| 154 |
+
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
|
| 155 |
+
void band(void* c, const void* a, const void* b, size_t n) {
|
| 156 |
+
auto tc = static_cast<T*>(c);
|
| 157 |
+
auto ta = static_cast<const T*>(a);
|
| 158 |
+
auto tb = static_cast<const T*>(b);
|
| 159 |
+
for (const auto i : c10::irange(n)) {
|
| 160 |
+
tc[i] = ta[i] & tb[i];
|
| 161 |
+
}
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
// Bitwise OR with SFINAE guard for integral types.
|
| 165 |
+
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
|
| 166 |
+
void bor(void* c, const void* a, const void* b, size_t n) {
|
| 167 |
+
auto tc = static_cast<T*>(c);
|
| 168 |
+
auto ta = static_cast<const T*>(a);
|
| 169 |
+
auto tb = static_cast<const T*>(b);
|
| 170 |
+
for (const auto i : c10::irange(n)) {
|
| 171 |
+
tc[i] = ta[i] | tb[i];
|
| 172 |
+
}
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
// Bitwise XOR with SFINAE guard for integral types.
|
| 176 |
+
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
|
| 177 |
+
void bxor(void* c, const void* a, const void* b, size_t n) {
|
| 178 |
+
auto tc = static_cast<T*>(c);
|
| 179 |
+
auto ta = static_cast<const T*>(a);
|
| 180 |
+
auto tb = static_cast<const T*>(b);
|
| 181 |
+
for (const auto i : c10::irange(n)) {
|
| 182 |
+
tc[i] = ta[i] ^ tb[i];
|
| 183 |
+
}
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
template <typename T, std::enable_if_t<std::is_integral_v<T>, int> = 0>
|
| 187 |
+
ReduceFunc toFunction(const ReduceOp& r) {
|
| 188 |
+
switch (r) {
|
| 189 |
+
case ReduceOp::SUM:
|
| 190 |
+
case ReduceOp::AVG:
|
| 191 |
+
return ReduceFunc(&::gloo::sum<T>);
|
| 192 |
+
case ReduceOp::PRODUCT:
|
| 193 |
+
return ReduceFunc(&::gloo::product<T>);
|
| 194 |
+
case ReduceOp::MIN:
|
| 195 |
+
return ReduceFunc(&::gloo::min<T>);
|
| 196 |
+
case ReduceOp::MAX:
|
| 197 |
+
return ReduceFunc(&::gloo::max<T>);
|
| 198 |
+
case ReduceOp::BAND:
|
| 199 |
+
return ReduceFunc(&band<T>);
|
| 200 |
+
case ReduceOp::BOR:
|
| 201 |
+
return ReduceFunc(&bor<T>);
|
| 202 |
+
case ReduceOp::BXOR:
|
| 203 |
+
return ReduceFunc(&bxor<T>);
|
| 204 |
+
case ReduceOp::PREMUL_SUM:
|
| 205 |
+
TORCH_CHECK(false, "Cannot use ReduceOp.PREMUL_SUM with Gloo");
|
| 206 |
+
break;
|
| 207 |
+
case ReduceOp::UNUSED:
|
| 208 |
+
default:
|
| 209 |
+
break;
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
TORCH_CHECK(false, "Unhandled ReduceOp");
|
| 213 |
+
}
|
| 214 |
+
|
| 215 |
+
template <typename T, typename O>
|
| 216 |
+
void setInputs(O& opts, std::vector<at::Tensor>& tensors) {
|
| 217 |
+
opts.setInputs(getDataPointers<T>(tensors), tensors[0].numel());
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
template <typename T, typename O>
|
| 221 |
+
void setInput(O& opts, at::Tensor& tensor) {
|
| 222 |
+
opts.setInput(getDataPointer<T>(tensor), tensor.numel());
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
template <typename T, typename O>
|
| 226 |
+
void setInput(O& opts, at::Tensor& tensor, std::vector<size_t>& counts) {
|
| 227 |
+
opts.setInput(getDataPointer<T>(tensor), counts);
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
template <typename T, typename O>
|
| 231 |
+
void setInput(O& opts, at::Tensor& tensor, std::vector<int64_t>& counts) {
|
| 232 |
+
opts.setInput(getDataPointer<T>(tensor), counts);
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
template <typename T, typename O>
|
| 236 |
+
void setOutputs(O& opts, std::vector<at::Tensor>& tensors, int64_t count) {
|
| 237 |
+
opts.setOutputs(getDataPointers<T>(tensors), count);
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
template <typename T, typename O>
|
| 241 |
+
void setOutput(O& opts, at::Tensor& tensor) {
|
| 242 |
+
opts.setOutput(getDataPointer<T>(tensor), tensor.numel());
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
template <typename T, typename O>
|
| 246 |
+
void setOutput(O& opts, at::Tensor& tensor, std::vector<size_t>& counts) {
|
| 247 |
+
opts.setOutput(getDataPointer<T>(tensor), counts);
|
| 248 |
+
}
|
| 249 |
+
|
| 250 |
+
template <typename T, typename O>
|
| 251 |
+
void setOutput(O& opts, at::Tensor& tensor, std::vector<int64_t>& counts) {
|
| 252 |
+
opts.setOutput(getDataPointer<T>(tensor), counts);
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
static at::Tensor pinnedLike(at::Tensor& tensor) {
|
| 256 |
+
auto* allocator = at::detail::getCUDAHooks().getPinnedMemoryAllocator();
|
| 257 |
+
auto storage = c10::Storage(
|
| 258 |
+
c10::Storage::use_byte_size_t(),
|
| 259 |
+
static_cast<int64_t>(at::detail::computeStorageNbytes(
|
| 260 |
+
tensor.sizes(), tensor.strides(), tensor.dtype().itemsize())),
|
| 261 |
+
allocator,
|
| 262 |
+
/*resizable=*/false);
|
| 263 |
+
return at::empty({0}, tensor.options().device(at::kCPU))
|
| 264 |
+
.set_(storage, 0, tensor.sizes(), tensor.strides());
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
class AsyncAllreduceWork : public ProcessGroupGloo::AsyncWork {
|
| 268 |
+
public:
|
| 269 |
+
AsyncAllreduceWork(
|
| 270 |
+
std::shared_ptr<gloo::Context> context,
|
| 271 |
+
std::vector<at::Tensor>& inputs,
|
| 272 |
+
ReduceOp reduceOp,
|
| 273 |
+
uint32_t tag,
|
| 274 |
+
uint64_t seq,
|
| 275 |
+
std::chrono::milliseconds timeout)
|
| 276 |
+
: ProcessGroupGloo::AsyncWork(
|
| 277 |
+
std::move(context),
|
| 278 |
+
{inputs},
|
| 279 |
+
OpType::ALLREDUCE,
|
| 280 |
+
seq,
|
| 281 |
+
timeout,
|
| 282 |
+
"gloo:all_reduce",
|
| 283 |
+
inputs),
|
| 284 |
+
inputs(inputs),
|
| 285 |
+
reduceOp(std::move(reduceOp)),
|
| 286 |
+
tag(tag) {}
|
| 287 |
+
|
| 288 |
+
std::vector<at::Tensor> inputs;
|
| 289 |
+
const ReduceOp reduceOp;
|
| 290 |
+
const uint32_t tag;
|
| 291 |
+
|
| 292 |
+
void allreduce(std::vector<at::Tensor>& tensors) {
|
| 293 |
+
auto tensor = tensors[0];
|
| 294 |
+
if (tensor.is_complex()) {
|
| 295 |
+
TORCH_CHECK(
|
| 296 |
+
c10d::isComplexViewAsRealAllowed(reduceOp),
|
| 297 |
+
"all_reduce does not support",
|
| 298 |
+
reduceOp,
|
| 299 |
+
"on complex tensors");
|
| 300 |
+
tensor = at::view_as_real(tensor);
|
| 301 |
+
}
|
| 302 |
+
gloo::AllreduceOptions opts(context_);
|
| 303 |
+
const auto& scalarType = tensor.scalar_type();
|
| 304 |
+
opts.setReduceFunction(getFunction(scalarType, reduceOp));
|
| 305 |
+
opts.setTag(tag);
|
| 306 |
+
opts.setTimeout(getTimeout());
|
| 307 |
+
// Use tensor.numel() instead of tensors[0].numel() to
|
| 308 |
+
// get the right number of elements when tensors[0] is complex
|
| 309 |
+
GENERATE_ALL_TYPES(scalarType, setOutputs, opts, tensors, tensor.numel());
|
| 310 |
+
gloo::allreduce(opts);
|
| 311 |
+
|
| 312 |
+
// Gloo doesn't support AVG so we use SUM + division.
|
| 313 |
+
if (reduceOp == ReduceOp::AVG) {
|
| 314 |
+
tensors[0] /= context_->size;
|
| 315 |
+
}
|
| 316 |
+
}
|
| 317 |
+
|
| 318 |
+
const std::vector<at::Tensor> getInputTensors() override {
|
| 319 |
+
return inputs;
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
const std::vector<at::Tensor> getOutputTensors() override {
|
| 323 |
+
return inputs;
|
| 324 |
+
}
|
| 325 |
+
|
| 326 |
+
void run() override {
|
| 327 |
+
allreduce(inputs);
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
template <typename T>
|
| 331 |
+
void getFunction(gloo::AllreduceOptions::Func& fn, const ReduceOp op) {
|
| 332 |
+
fn = toFunction<T>(op);
|
| 333 |
+
}
|
| 334 |
+
|
| 335 |
+
gloo::AllreduceOptions::Func getFunction(
|
| 336 |
+
const at::ScalarType& dtype,
|
| 337 |
+
const ReduceOp& op) {
|
| 338 |
+
gloo::AllreduceOptions::Func fn;
|
| 339 |
+
GENERATE_ALL_TYPES(dtype, getFunction, fn, op);
|
| 340 |
+
return fn;
|
| 341 |
+
}
|
| 342 |
+
};
|
| 343 |
+
|
| 344 |
+
class AsyncAllreduceCoalescedWork : public AsyncAllreduceWork {
|
| 345 |
+
public:
|
| 346 |
+
AsyncAllreduceCoalescedWork(
|
| 347 |
+
const std::shared_ptr<gloo::Context>& context,
|
| 348 |
+
std::vector<at::Tensor>& inputs,
|
| 349 |
+
ReduceOp reduceOp,
|
| 350 |
+
uint32_t tag,
|
| 351 |
+
uint64_t seq,
|
| 352 |
+
std::chrono::milliseconds timeout)
|
| 353 |
+
: AsyncAllreduceWork(
|
| 354 |
+
context,
|
| 355 |
+
inputs,
|
| 356 |
+
std::move(reduceOp),
|
| 357 |
+
tag,
|
| 358 |
+
seq,
|
| 359 |
+
timeout) {}
|
| 360 |
+
|
| 361 |
+
void run() override {
|
| 362 |
+
allreduceCoalesced(inputs);
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
private:
|
| 366 |
+
void allreduceCoalesced(std::vector<at::Tensor>& tensors) {
|
| 367 |
+
// reduce coalesced, flattened tensors.
|
| 368 |
+
at::Tensor coalescedTensor = flattenDenseTensors(tensors);
|
| 369 |
+
std::vector<at::Tensor> allreduceInput = {coalescedTensor};
|
| 370 |
+
allreduce(allreduceInput);
|
| 371 |
+
|
| 372 |
+
// separate and reshape tensors.
|
| 373 |
+
size_t offset = 0;
|
| 374 |
+
for (at::Tensor& tensor : tensors) {
|
| 375 |
+
const int64_t tensorNumel = tensor.numel();
|
| 376 |
+
const c10::IntArrayRef tensorShape = tensor.sizes();
|
| 377 |
+
tensor.copy_(coalescedTensor.slice(0, offset, offset + tensorNumel)
|
| 378 |
+
.view(tensorShape));
|
| 379 |
+
offset += tensorNumel;
|
| 380 |
+
}
|
| 381 |
+
}
|
| 382 |
+
};
|
| 383 |
+
|
| 384 |
+
class AsyncSparseAllreduceWork : public ProcessGroupGloo::AsyncWork {
|
| 385 |
+
public:
|
| 386 |
+
AsyncSparseAllreduceWork(
|
| 387 |
+
std::shared_ptr<gloo::Context> context,
|
| 388 |
+
std::vector<at::Tensor>& inputs,
|
| 389 |
+
uint32_t tag,
|
| 390 |
+
uint64_t seq,
|
| 391 |
+
std::chrono::milliseconds timeout)
|
| 392 |
+
: ProcessGroupGloo::AsyncWork(
|
| 393 |
+
std::move(context),
|
| 394 |
+
{inputs},
|
| 395 |
+
OpType::_ALLREDUCE_SPARSE,
|
| 396 |
+
seq,
|
| 397 |
+
timeout,
|
| 398 |
+
"gloo:sparse_all_reduce",
|
| 399 |
+
inputs),
|
| 400 |
+
inputs(inputs),
|
| 401 |
+
tag(tag) {}
|
| 402 |
+
|
| 403 |
+
std::vector<at::Tensor> inputs;
|
| 404 |
+
const uint32_t tag;
|
| 405 |
+
|
| 406 |
+
// We share dimensionality about the sparse tensors before collecting
|
| 407 |
+
// their contents. We assume here that the maximum number of sparse
|
| 408 |
+
// and dense dimensions is 4. This is stored in a contiguous piece of
|
| 409 |
+
// memory so that we can easily run allgather on it.
|
| 410 |
+
//
|
| 411 |
+
// The layout of this memory is as follows:
|
| 412 |
+
//
|
| 413 |
+
// - [0:4]: sparse dims
|
| 414 |
+
// - [4:8]: dense dims
|
| 415 |
+
// - [8]: nnz
|
| 416 |
+
//
|
| 417 |
+
class SparseTensorMetadata {
|
| 418 |
+
public:
|
| 419 |
+
static constexpr auto dim = 9;
|
| 420 |
+
|
| 421 |
+
// Construct from an existing metadata tensor to facilitate structured
|
| 422 |
+
// access to metadata from peers, after gathering it.
|
| 423 |
+
explicit SparseTensorMetadata(at::Tensor metadata)
|
| 424 |
+
: metadata_(std::move(metadata)),
|
| 425 |
+
data_(metadata_.mutable_data_ptr<int64_t>()) {
|
| 426 |
+
AT_ASSERT(metadata_.scalar_type() == at::kLong);
|
| 427 |
+
AT_ASSERT(metadata_.dim() == 1);
|
| 428 |
+
AT_ASSERT(metadata_.size(0) == dim);
|
| 429 |
+
}
|
| 430 |
+
|
| 431 |
+
// Populate the metadata.
|
| 432 |
+
void populate_from_sparse_tensor(const at::Tensor& tensor) {
|
| 433 |
+
const auto sparse_dim = tensor.sparse_dim();
|
| 434 |
+
AT_ASSERT(sparse_dim <= 4);
|
| 435 |
+
for (const auto i : c10::irange(4)) {
|
| 436 |
+
if (i < sparse_dim) {
|
| 437 |
+
data_[i] = tensor.size(i);
|
| 438 |
+
}
|
| 439 |
+
}
|
| 440 |
+
const auto dense_dim = tensor.dense_dim();
|
| 441 |
+
AT_ASSERT(dense_dim <= 4);
|
| 442 |
+
for (const auto i : c10::irange(4)) {
|
| 443 |
+
if (i < dense_dim) {
|
| 444 |
+
data_[i + 4] = tensor.size(sparse_dim + i);
|
| 445 |
+
}
|
| 446 |
+
}
|
| 447 |
+
data_[8] = tensor._nnz();
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
std::vector<int64_t> sizes() const {
|
| 451 |
+
std::vector<int64_t> sizes;
|
| 452 |
+
// Sparse sizes
|
| 453 |
+
for (const auto i : c10::irange(4)) {
|
| 454 |
+
if (data_[i] <= 0) {
|
| 455 |
+
break;
|
| 456 |
+
}
|
| 457 |
+
sizes.push_back(data_[i]);
|
| 458 |
+
}
|
| 459 |
+
// Dense sizes
|
| 460 |
+
for (const auto i : c10::irange(4, 8)) {
|
| 461 |
+
if (data_[i] <= 0) {
|
| 462 |
+
break;
|
| 463 |
+
}
|
| 464 |
+
sizes.push_back(data_[i]);
|
| 465 |
+
}
|
| 466 |
+
return sizes;
|
| 467 |
+
}
|
| 468 |
+
|
| 469 |
+
int64_t nnz() const {
|
| 470 |
+
return data_[8];
|
| 471 |
+
}
|
| 472 |
+
|
| 473 |
+
protected:
|
| 474 |
+
at::Tensor metadata_;
|
| 475 |
+
int64_t* data_;
|
| 476 |
+
};
|
| 477 |
+
|
| 478 |
+
// Sparse allreduce is implemented with allgather on indices and values.
|
| 479 |
+
// Every process then sums the resulting sparse tensors locally.
|
| 480 |
+
// The nnz for sparse tensors may be different across processes, so first
|
| 481 |
+
// we run allgather on the nnz, and then allgather with max(nnz).
|
| 482 |
+
at::Tensor allreduce(std::vector<at::Tensor>& tensors) {
|
| 483 |
+
// TODO: This is a massive hack! There is some confusion about
|
| 484 |
+
// Variable/Tensor inside the body of this function. Turning off
|
| 485 |
+
// grad smooths over the confusion for now. This fixes
|
| 486 |
+
// test/test_c10d_gloo.py ProcessGroupGlooTest.test_sparse_allreduce_basics
|
| 487 |
+
//
|
| 488 |
+
// The correct fix is to stop allocating tensors that are not variables,
|
| 489 |
+
// but to conveniently do this c10d must depend on torch not ATen
|
| 490 |
+
at::AutoDispatchBelowAutograd guard;
|
| 491 |
+
auto input = tensors[0];
|
| 492 |
+
|
| 493 |
+
// Perform local reduction if we have multiple inputs.
|
| 494 |
+
for (const auto i : c10::irange(1, tensors.size())) {
|
| 495 |
+
input += tensors[i];
|
| 496 |
+
}
|
| 497 |
+
|
| 498 |
+
// Need to coalesce before we can access indices and values.
|
| 499 |
+
input = input.coalesce();
|
| 500 |
+
|
| 501 |
+
// Gather metadata information from all ranks.
|
| 502 |
+
auto metadata = allgather_metadata(input);
|
| 503 |
+
|
| 504 |
+
// Sanity check dimensionality across ranks.
|
| 505 |
+
{
|
| 506 |
+
const auto expected = metadata[context_->rank].sizes();
|
| 507 |
+
for (const auto i : c10::irange(context_->size)) {
|
| 508 |
+
if (i == context_->rank) {
|
| 509 |
+
continue;
|
| 510 |
+
}
|
| 511 |
+
const auto actual = metadata[i].sizes();
|
| 512 |
+
TORCH_CHECK(actual == expected, "Sparse dimensions do not match");
|
| 513 |
+
}
|
| 514 |
+
}
|
| 515 |
+
|
| 516 |
+
// Gather all indices and all values.
|
| 517 |
+
auto indices = allgather_indices(input, metadata);
|
| 518 |
+
auto values = allgather_values(input, metadata);
|
| 519 |
+
|
| 520 |
+
// Perform global reduction.
|
| 521 |
+
AT_ASSERT(static_cast<int>(indices.size()) == context_->size);
|
| 522 |
+
AT_ASSERT(static_cast<int>(values.size()) == context_->size);
|
| 523 |
+
auto output = at::sparse_coo_tensor(
|
| 524 |
+
indices[0], values[0], input.sizes(), input.options());
|
| 525 |
+
for (const auto i : c10::irange(1, context_->size)) {
|
| 526 |
+
output += at::sparse_coo_tensor(
|
| 527 |
+
indices[i], values[i], input.sizes(), input.options());
|
| 528 |
+
}
|
| 529 |
+
|
| 530 |
+
// Coalesce for good measure.
|
| 531 |
+
return output.coalesce();
|
| 532 |
+
}
|
| 533 |
+
|
| 534 |
+
void run() override {
|
| 535 |
+
auto output = allreduce(inputs);
|
| 536 |
+
|
| 537 |
+
// This copy is needed when we run a multi-gpu version of reduce (multiple
|
| 538 |
+
// inputs per rank).
|
| 539 |
+
for (const auto i : c10::irange(inputs.size())) {
|
| 540 |
+
inputs[i].copy_(output);
|
| 541 |
+
}
|
| 542 |
+
}
|
| 543 |
+
|
| 544 |
+
const std::vector<at::Tensor> getInputTensors() override {
|
| 545 |
+
return inputs;
|
| 546 |
+
}
|
| 547 |
+
|
| 548 |
+
const std::vector<at::Tensor> getOutputTensors() override {
|
| 549 |
+
return inputs;
|
| 550 |
+
}
|
| 551 |
+
|
| 552 |
+
private:
|
| 553 |
+
std::vector<SparseTensorMetadata> allgather_metadata(
|
| 554 |
+
const at::Tensor& tensor) {
|
| 555 |
+
auto buffer =
|
| 556 |
+
at::zeros({context_->size, SparseTensorMetadata::dim}, at::kLong);
|
| 557 |
+
|
| 558 |
+
// Prepare metadata vector (1 entry per rank)
|
| 559 |
+
std::vector<SparseTensorMetadata> metadata;
|
| 560 |
+
metadata.reserve(context_->size);
|
| 561 |
+
for (const auto i : c10::irange(context_->size)) {
|
| 562 |
+
metadata.emplace_back(buffer.select(0, i));
|
| 563 |
+
}
|
| 564 |
+
|
| 565 |
+
// Populate data for this rank
|
| 566 |
+
metadata[context_->rank].populate_from_sparse_tensor(tensor);
|
| 567 |
+
|
| 568 |
+
// Allgather metadata
|
| 569 |
+
gloo::AllgatherOptions opts(context_);
|
| 570 |
+
opts.setOutput(buffer.mutable_data_ptr<int64_t>(), buffer.numel());
|
| 571 |
+
opts.setTag(tag);
|
| 572 |
+
opts.setTimeout(getTimeout());
|
| 573 |
+
gloo::allgather(opts);
|
| 574 |
+
|
| 575 |
+
return metadata;
|
| 576 |
+
}
|
| 577 |
+
|
| 578 |
+
std::vector<at::Tensor> allgather_indices(
|
| 579 |
+
const at::Tensor& tensor,
|
| 580 |
+
const std::vector<SparseTensorMetadata>& metadata) {
|
| 581 |
+
const auto sparseDim = tensor.sparse_dim();
|
| 582 |
+
|
| 583 |
+
std::vector<size_t> counts(context_->size);
|
| 584 |
+
size_t totalSize = 0;
|
| 585 |
+
for (const auto i : c10::irange(metadata.size())) {
|
| 586 |
+
counts[i] = metadata[i].nnz() * sparseDim;
|
| 587 |
+
totalSize += counts[i];
|
| 588 |
+
}
|
| 589 |
+
|
| 590 |
+
auto output = at::empty({static_cast<int64_t>(totalSize)}, at::kLong);
|
| 591 |
+
|
| 592 |
+
// tensors copied from cuda may not be contiguous, get a contiguous
|
| 593 |
+
// tensor before use its data_ptr
|
| 594 |
+
auto input = tensor.indices().contiguous();
|
| 595 |
+
|
| 596 |
+
// Allgatherv indices.
|
| 597 |
+
gloo::AllgathervOptions opts(context_);
|
| 598 |
+
opts.setInput(
|
| 599 |
+
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
|
| 600 |
+
const_cast<int64_t*>(input.const_data_ptr<int64_t>()),
|
| 601 |
+
input.numel());
|
| 602 |
+
opts.setOutput(output.mutable_data_ptr<int64_t>(), counts);
|
| 603 |
+
opts.setTag(tag);
|
| 604 |
+
opts.setTimeout(getTimeout());
|
| 605 |
+
gloo::allgatherv(opts);
|
| 606 |
+
|
| 607 |
+
// Compile indices tensor per rank.
|
| 608 |
+
std::vector<at::Tensor> indices;
|
| 609 |
+
indices.reserve(metadata.size());
|
| 610 |
+
int64_t offset = 0;
|
| 611 |
+
for (const auto& i : metadata) {
|
| 612 |
+
const auto nnz = i.nnz();
|
| 613 |
+
const auto numel = sparseDim * nnz;
|
| 614 |
+
indices.push_back(
|
| 615 |
+
output.narrow(0, offset, numel).reshape({sparseDim, nnz}));
|
| 616 |
+
offset += numel;
|
| 617 |
+
}
|
| 618 |
+
|
| 619 |
+
return indices;
|
| 620 |
+
}
|
| 621 |
+
|
| 622 |
+
std::vector<at::Tensor> allgather_values(
|
| 623 |
+
const at::Tensor& tensor,
|
| 624 |
+
const std::vector<SparseTensorMetadata>& metadata) {
|
| 625 |
+
// There are nnz #dense_dim()-dimensional tensors per rank.
|
| 626 |
+
const auto valueShape = tensor.sizes().slice(tensor.sparse_dim());
|
| 627 |
+
int64_t denseNumel = 1;
|
| 628 |
+
for (auto dim : valueShape) {
|
| 629 |
+
denseNumel *= dim;
|
| 630 |
+
}
|
| 631 |
+
|
| 632 |
+
std::vector<size_t> counts(context_->size);
|
| 633 |
+
int64_t totalSize = 0;
|
| 634 |
+
for (const auto i : c10::irange(metadata.size())) {
|
| 635 |
+
counts[i] = metadata[i].nnz() * denseNumel;
|
| 636 |
+
totalSize += static_cast<int64_t>(counts[i]);
|
| 637 |
+
}
|
| 638 |
+
|
| 639 |
+
auto output = at::empty({totalSize}, tensor.scalar_type());
|
| 640 |
+
|
| 641 |
+
// Allgatherv indices.
|
| 642 |
+
gloo::AllgathervOptions opts(context_);
|
| 643 |
+
// tensors copied from cuda may not be contiguous, get a contiguous
|
| 644 |
+
// tensor before use its data_ptr
|
| 645 |
+
at::Tensor valueTensor = tensor.values().contiguous();
|
| 646 |
+
GENERATE_ALL_TYPES(valueTensor.scalar_type(), setInput, opts, valueTensor);
|
| 647 |
+
GENERATE_ALL_TYPES(
|
| 648 |
+
valueTensor.scalar_type(), setOutput, opts, output, counts);
|
| 649 |
+
opts.setTag(tag);
|
| 650 |
+
opts.setTimeout(getTimeout());
|
| 651 |
+
gloo::allgatherv(opts);
|
| 652 |
+
|
| 653 |
+
// Compile values tensor per rank.
|
| 654 |
+
std::vector<at::Tensor> values;
|
| 655 |
+
values.reserve(metadata.size());
|
| 656 |
+
int64_t offset = 0;
|
| 657 |
+
for (const auto& i : metadata) {
|
| 658 |
+
const auto nnz = i.nnz();
|
| 659 |
+
const auto numel = denseNumel * nnz;
|
| 660 |
+
auto tensorShape = std::vector<int64_t>({(int64_t)nnz});
|
| 661 |
+
std::copy(
|
| 662 |
+
valueShape.begin(),
|
| 663 |
+
valueShape.end(),
|
| 664 |
+
std::back_inserter(tensorShape));
|
| 665 |
+
values.push_back(output.narrow(0, offset, numel).reshape(tensorShape));
|
| 666 |
+
offset += numel;
|
| 667 |
+
}
|
| 668 |
+
|
| 669 |
+
return values;
|
| 670 |
+
}
|
| 671 |
+
};
|
| 672 |
+
|
| 673 |
+
} // namespace c10d
|
| 674 |
+
|
| 675 |
+
#endif
|
| 676 |
+
|
| 677 |
+
#else
|
| 678 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 679 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupMPI.hpp
ADDED
|
@@ -0,0 +1,278 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#ifdef USE_C10D_MPI
|
| 5 |
+
|
| 6 |
+
#include <condition_variable>
|
| 7 |
+
#include <deque>
|
| 8 |
+
#include <exception>
|
| 9 |
+
#include <memory>
|
| 10 |
+
#include <mutex>
|
| 11 |
+
#include <thread>
|
| 12 |
+
#include <vector>
|
| 13 |
+
|
| 14 |
+
#include <ATen/core/ivalue.h>
|
| 15 |
+
#include <ATen/core/ivalue_inl.h>
|
| 16 |
+
|
| 17 |
+
#include <torch/csrc/distributed/c10d/Backend.hpp>
|
| 18 |
+
#include <torch/csrc/distributed/c10d/Types.hpp>
|
| 19 |
+
#include <torch/csrc/distributed/c10d/Utils.hpp>
|
| 20 |
+
|
| 21 |
+
#include <mpi.h>
|
| 22 |
+
|
| 23 |
+
namespace c10d {
|
| 24 |
+
|
| 25 |
+
constexpr const char* MPI_BACKEND_NAME = "mpi";
|
| 26 |
+
|
| 27 |
+
// WorkEntry is the state associated with a single MPI run instance.
|
| 28 |
+
// It include the source Tensor list and destination Tensor list, as well as
|
| 29 |
+
// The actual run function that will operate either on src or dst or both.
|
| 30 |
+
struct WorkEntry {
|
| 31 |
+
explicit WorkEntry(
|
| 32 |
+
std::vector<at::Tensor>* srcPtr,
|
| 33 |
+
std::vector<at::Tensor>* dstPtr,
|
| 34 |
+
std::function<void(std::unique_ptr<WorkEntry>&)> run)
|
| 35 |
+
: dst(dstPtr ? *dstPtr : std::vector<at::Tensor>()), run(std::move(run)) {
|
| 36 |
+
if (srcPtr) {
|
| 37 |
+
src = *srcPtr;
|
| 38 |
+
}
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
// Not copyable
|
| 42 |
+
WorkEntry(const WorkEntry&) = delete;
|
| 43 |
+
// Not copy assignable
|
| 44 |
+
WorkEntry& operator=(const WorkEntry&) = delete;
|
| 45 |
+
|
| 46 |
+
// For input and output tensors (in-place), we will always use src
|
| 47 |
+
std::vector<at::Tensor> src;
|
| 48 |
+
|
| 49 |
+
// Copy of user provided outputs.
|
| 50 |
+
const std::vector<at::Tensor> dst;
|
| 51 |
+
|
| 52 |
+
// src rank returned, for recv only
|
| 53 |
+
int* srcRank = nullptr;
|
| 54 |
+
std::function<void(std::unique_ptr<WorkEntry>&)> run;
|
| 55 |
+
};
|
| 56 |
+
|
| 57 |
+
// ProcessGroupMPI implements MPI bindings for c10d.
|
| 58 |
+
//
|
| 59 |
+
// All functions on this class are expected to be called in the same
|
| 60 |
+
// order across processes in the group. This is the only way that we
|
| 61 |
+
// can guarantee to match up the same calls across processes.
|
| 62 |
+
//
|
| 63 |
+
// All MPI functions provided by this class is asynchronously scheduled on a
|
| 64 |
+
// Worker thread. Therefore, ProcessGroupMPI requires the MPI implementation
|
| 65 |
+
// that is used to have a minimum thread support value of MPI_THREAD_SERIALIZED.
|
| 66 |
+
// That is, The process may be multi-threaded, and multiple threads may make
|
| 67 |
+
// MPI calls, but only one at a time: MPI calls are not made concurrently from
|
| 68 |
+
// two distinct threads (all MPI calls are serialized). However, with
|
| 69 |
+
// MPI_THREAD_SERIALIZED, ProcessGroupMPI will only support a single process
|
| 70 |
+
// group. In other words, no more than 1 process group can be created globally.
|
| 71 |
+
//
|
| 72 |
+
// If you would like to use multiple ProcessGroupMPI, it requires your MPI
|
| 73 |
+
// implementation to have a thread support value of MPI_THREAD_MULTIPLE, that
|
| 74 |
+
// is, multiple threads may call MPI, with no restriction.
|
| 75 |
+
//
|
| 76 |
+
// Also note that ProcessGroupMPI only supports a single Tensor operation. In
|
| 77 |
+
// other words, the size of the input Tensor vector should always be 1.
|
| 78 |
+
//
|
| 79 |
+
// CUDA tensor can be supported if the MPI used is CUDA-aware MPI, and
|
| 80 |
+
// ProcessGroupMPI will automatically detect this support.
|
| 81 |
+
class TORCH_API ProcessGroupMPI : public Backend {
|
| 82 |
+
public:
|
| 83 |
+
class WorkMPI : public Work {
|
| 84 |
+
public:
|
| 85 |
+
explicit WorkMPI(
|
| 86 |
+
std::vector<at::Tensor> outputTensors,
|
| 87 |
+
const char* profilingTitle = nullptr,
|
| 88 |
+
const std::optional<std::vector<at::Tensor>>& inputTensors =
|
| 89 |
+
std::nullopt)
|
| 90 |
+
: Work(-1, OpType::UNKNOWN, profilingTitle, inputTensors),
|
| 91 |
+
outputTensors_(std::move(outputTensors)),
|
| 92 |
+
future_(c10::make_intrusive<at::ivalue::Future>(
|
| 93 |
+
c10::ListType::create(c10::TensorType::get()))) {}
|
| 94 |
+
|
| 95 |
+
std::vector<at::Tensor> result() override;
|
| 96 |
+
|
| 97 |
+
c10::intrusive_ptr<c10::ivalue::Future> getFuture() override;
|
| 98 |
+
|
| 99 |
+
protected:
|
| 100 |
+
friend class ProcessGroupMPI;
|
| 101 |
+
|
| 102 |
+
private:
|
| 103 |
+
void finishWorkMPI();
|
| 104 |
+
void finishWorkMPIError(const std::exception_ptr& eptr);
|
| 105 |
+
|
| 106 |
+
std::vector<at::Tensor> outputTensors_;
|
| 107 |
+
c10::intrusive_ptr<at::ivalue::Future> future_;
|
| 108 |
+
};
|
| 109 |
+
|
| 110 |
+
class AsyncWork : public Work {
|
| 111 |
+
public:
|
| 112 |
+
AsyncWork(
|
| 113 |
+
MPI_Request request,
|
| 114 |
+
std::vector<at::Tensor> outputTensors,
|
| 115 |
+
const char* profilingTitle = nullptr,
|
| 116 |
+
const std::optional<std::vector<at::Tensor>>& inputTensors =
|
| 117 |
+
std::nullopt);
|
| 118 |
+
|
| 119 |
+
~AsyncWork() override;
|
| 120 |
+
|
| 121 |
+
bool isCompleted() override;
|
| 122 |
+
|
| 123 |
+
bool isSuccess() const override;
|
| 124 |
+
|
| 125 |
+
int sourceRank() const override;
|
| 126 |
+
|
| 127 |
+
bool wait(std::chrono::milliseconds timeout = kUnsetTimeout) override;
|
| 128 |
+
|
| 129 |
+
void abort() override;
|
| 130 |
+
|
| 131 |
+
std::vector<at::Tensor> result() override;
|
| 132 |
+
|
| 133 |
+
protected:
|
| 134 |
+
void populateException();
|
| 135 |
+
|
| 136 |
+
private:
|
| 137 |
+
const std::vector<at::Tensor> outputTensors_;
|
| 138 |
+
MPI_Request request_;
|
| 139 |
+
MPI_Status status_{};
|
| 140 |
+
};
|
| 141 |
+
|
| 142 |
+
// Constructor will spawn up the worker thread loop
|
| 143 |
+
explicit ProcessGroupMPI(int rank, int size, MPI_Comm pgComm);
|
| 144 |
+
|
| 145 |
+
~ProcessGroupMPI() override;
|
| 146 |
+
|
| 147 |
+
// Abort the MPI program, needs to be called when exception is detected
|
| 148 |
+
void abort() override;
|
| 149 |
+
|
| 150 |
+
const std::string getBackendName() const override {
|
| 151 |
+
return std::string(MPI_BACKEND_NAME);
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
c10::intrusive_ptr<Work> broadcast(
|
| 155 |
+
std::vector<at::Tensor>& data,
|
| 156 |
+
const BroadcastOptions& opts = BroadcastOptions()) override;
|
| 157 |
+
|
| 158 |
+
c10::intrusive_ptr<Work> allreduce(
|
| 159 |
+
std::vector<at::Tensor>& tensors,
|
| 160 |
+
const AllreduceOptions& opts = AllreduceOptions()) override;
|
| 161 |
+
|
| 162 |
+
c10::intrusive_ptr<Work> allreduce_coalesced(
|
| 163 |
+
std::vector<at::Tensor>& tensors,
|
| 164 |
+
const AllreduceCoalescedOptions& opts =
|
| 165 |
+
AllreduceCoalescedOptions()) override;
|
| 166 |
+
|
| 167 |
+
c10::intrusive_ptr<Work> reduce(
|
| 168 |
+
std::vector<at::Tensor>& tensors,
|
| 169 |
+
const ReduceOptions& opts = ReduceOptions()) override;
|
| 170 |
+
|
| 171 |
+
c10::intrusive_ptr<Work> allgather(
|
| 172 |
+
std::vector<std::vector<at::Tensor>>& outputTensors,
|
| 173 |
+
std::vector<at::Tensor>& inputTensors,
|
| 174 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 175 |
+
|
| 176 |
+
c10::intrusive_ptr<Work> _allgather_base(
|
| 177 |
+
at::Tensor& outputbuffer,
|
| 178 |
+
at::Tensor& inputbuffer,
|
| 179 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 180 |
+
|
| 181 |
+
c10::intrusive_ptr<Work> allgather_coalesced(
|
| 182 |
+
std::vector<std::vector<at::Tensor>>& outputTensorLists,
|
| 183 |
+
std::vector<at::Tensor>& inputTensors,
|
| 184 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 185 |
+
|
| 186 |
+
c10::intrusive_ptr<Work> gather(
|
| 187 |
+
std::vector<std::vector<at::Tensor>>& outputTensors,
|
| 188 |
+
std::vector<at::Tensor>& inputTensors,
|
| 189 |
+
const GatherOptions& opts = GatherOptions()) override;
|
| 190 |
+
|
| 191 |
+
c10::intrusive_ptr<Work> scatter(
|
| 192 |
+
std::vector<at::Tensor>& outputTensors,
|
| 193 |
+
std::vector<std::vector<at::Tensor>>& inputTensors,
|
| 194 |
+
const ScatterOptions& opts = ScatterOptions()) override;
|
| 195 |
+
|
| 196 |
+
c10::intrusive_ptr<Work> reduce_scatter(
|
| 197 |
+
std::vector<at::Tensor>& outputTensors,
|
| 198 |
+
std::vector<std::vector<at::Tensor>>& inputTensors,
|
| 199 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override;
|
| 200 |
+
|
| 201 |
+
c10::intrusive_ptr<Work> _reduce_scatter_base(
|
| 202 |
+
at::Tensor& outputTensor,
|
| 203 |
+
at::Tensor& inputTensor,
|
| 204 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override;
|
| 205 |
+
|
| 206 |
+
c10::intrusive_ptr<Work> alltoall_base(
|
| 207 |
+
at::Tensor& outputTensor,
|
| 208 |
+
at::Tensor& inputTensor,
|
| 209 |
+
std::vector<int64_t>& outputSplitSizes,
|
| 210 |
+
std::vector<int64_t>& inputSplitSizes,
|
| 211 |
+
const AllToAllOptions& opts = AllToAllOptions()) override;
|
| 212 |
+
|
| 213 |
+
c10::intrusive_ptr<Work> alltoall(
|
| 214 |
+
std::vector<at::Tensor>& outputTensors,
|
| 215 |
+
std::vector<at::Tensor>& inputTensors,
|
| 216 |
+
const AllToAllOptions& opts = AllToAllOptions()) override;
|
| 217 |
+
|
| 218 |
+
c10::intrusive_ptr<Work> send(
|
| 219 |
+
std::vector<at::Tensor>& tensors,
|
| 220 |
+
int dstRank,
|
| 221 |
+
int tag) override;
|
| 222 |
+
|
| 223 |
+
c10::intrusive_ptr<Work> recv(
|
| 224 |
+
std::vector<at::Tensor>& tensors,
|
| 225 |
+
int srcRank,
|
| 226 |
+
int tag) override;
|
| 227 |
+
|
| 228 |
+
c10::intrusive_ptr<Work> recvAnysource(
|
| 229 |
+
std::vector<at::Tensor>& tensor,
|
| 230 |
+
int tag) override;
|
| 231 |
+
|
| 232 |
+
c10::intrusive_ptr<Work> barrier(
|
| 233 |
+
const BarrierOptions& opts = BarrierOptions()) override;
|
| 234 |
+
|
| 235 |
+
// Creating a new ProcessGroupMPI, will initialize MPI if not initialized
|
| 236 |
+
static c10::intrusive_ptr<ProcessGroupMPI> createProcessGroupMPI(
|
| 237 |
+
std::vector<int> ranks = {});
|
| 238 |
+
|
| 239 |
+
protected:
|
| 240 |
+
using WorkType =
|
| 241 |
+
std::tuple<std::unique_ptr<WorkEntry>, c10::intrusive_ptr<WorkMPI>>;
|
| 242 |
+
// Worker thread loop
|
| 243 |
+
void runLoop();
|
| 244 |
+
// Helper function that is called by the destructor
|
| 245 |
+
void destroy();
|
| 246 |
+
|
| 247 |
+
c10::intrusive_ptr<Work> enqueue(
|
| 248 |
+
std::unique_ptr<WorkEntry> entry,
|
| 249 |
+
const char* profilingTitle = nullptr,
|
| 250 |
+
const std::optional<std::vector<at::Tensor>>& inputTensors =
|
| 251 |
+
std::nullopt);
|
| 252 |
+
|
| 253 |
+
bool stop_{false};
|
| 254 |
+
|
| 255 |
+
std::mutex pgMutex_;
|
| 256 |
+
std::thread workerThread_;
|
| 257 |
+
|
| 258 |
+
std::deque<WorkType> queue_;
|
| 259 |
+
std::condition_variable queueProduceCV_;
|
| 260 |
+
std::condition_variable queueConsumeCV_;
|
| 261 |
+
|
| 262 |
+
// Global states
|
| 263 |
+
static void initMPIOnce();
|
| 264 |
+
static void mpiExit();
|
| 265 |
+
|
| 266 |
+
static std::mutex pgGlobalMutex_;
|
| 267 |
+
static int mpiThreadSupport_;
|
| 268 |
+
|
| 269 |
+
MPI_Comm pgComm_;
|
| 270 |
+
};
|
| 271 |
+
|
| 272 |
+
} // namespace c10d
|
| 273 |
+
|
| 274 |
+
#endif // USE_C10D_MPI
|
| 275 |
+
|
| 276 |
+
#else
|
| 277 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 278 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupNCCL.hpp
ADDED
|
@@ -0,0 +1,1547 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#ifdef USE_C10D_NCCL
|
| 5 |
+
|
| 6 |
+
#if defined(__linux__)
|
| 7 |
+
#include <fcntl.h>
|
| 8 |
+
#include <sys/stat.h>
|
| 9 |
+
#include <sys/types.h>
|
| 10 |
+
#include <unistd.h>
|
| 11 |
+
#endif
|
| 12 |
+
|
| 13 |
+
#include <atomic>
|
| 14 |
+
#include <chrono>
|
| 15 |
+
#include <deque>
|
| 16 |
+
#include <future>
|
| 17 |
+
#include <iostream>
|
| 18 |
+
#include <list>
|
| 19 |
+
#include <mutex>
|
| 20 |
+
#include <thread>
|
| 21 |
+
#include <unordered_map>
|
| 22 |
+
|
| 23 |
+
#include <torch/csrc/distributed/c10d/Backend.hpp>
|
| 24 |
+
#include <torch/csrc/distributed/c10d/NCCLUtils.hpp>
|
| 25 |
+
#include <torch/csrc/distributed/c10d/PrefixStore.hpp>
|
| 26 |
+
#include <torch/csrc/distributed/c10d/Store.hpp>
|
| 27 |
+
#include <torch/csrc/distributed/c10d/cuda/CUDAEventCache.hpp>
|
| 28 |
+
#include <torch/csrc/distributed/c10d/logger.hpp>
|
| 29 |
+
#include <torch/csrc/distributed/c10d/symm_mem/intra_node_comm.hpp>
|
| 30 |
+
|
| 31 |
+
#include <ATen/DynamicLibrary.h>
|
| 32 |
+
#include <ATen/cuda/CUDAContext.h>
|
| 33 |
+
#include <ATen/cuda/CUDAEvent.h>
|
| 34 |
+
#include <ATen/cuda/MemPool.h>
|
| 35 |
+
#include <c10/core/Stream.h>
|
| 36 |
+
#include <c10/core/StreamGuard.h>
|
| 37 |
+
#include <c10/cuda/CUDACachingAllocator.h>
|
| 38 |
+
#include <c10/cuda/CUDAGuard.h>
|
| 39 |
+
#include <c10/cuda/CUDAStream.h>
|
| 40 |
+
|
| 41 |
+
#include <torch/custom_class.h>
|
| 42 |
+
|
| 43 |
+
namespace c10d {
|
| 44 |
+
|
| 45 |
+
// Control broadcasting of NCCL uniqueId
|
| 46 |
+
static std::vector<std::string> TORCH_NCCL_BCAST_UNIQUEID = {
|
| 47 |
+
"TORCH_NCCL_BCAST_UNIQUEID"};
|
| 48 |
+
|
| 49 |
+
// Control EagerInit P2P serialization warning
|
| 50 |
+
static std::vector<std::string>
|
| 51 |
+
TORCH_NCCL_SHOW_EAGER_INIT_P2P_SERIALIZATION_WARNING = {
|
| 52 |
+
"TORCH_NCCL_SHOW_EAGER_INIT_P2P_SERIALIZATION_WARNING"};
|
| 53 |
+
|
| 54 |
+
// Control whether to always use high priority streams
|
| 55 |
+
static std::vector<std::string> TORCH_NCCL_HIGH_PRIORITY = {
|
| 56 |
+
"TORCH_NCCL_HIGH_PRIORITY"};
|
| 57 |
+
|
| 58 |
+
// Control whether or not wait() is blocking or non-blocking.
|
| 59 |
+
static std::vector<std::string> TORCH_NCCL_BLOCKING_WAIT = {
|
| 60 |
+
"TORCH_NCCL_BLOCKING_WAIT",
|
| 61 |
+
"NCCL_BLOCKING_WAIT"};
|
| 62 |
+
|
| 63 |
+
// TODO: We want to eventually remove this variable and make users to use
|
| 64 |
+
// the default value (3 - SkipCleanUp).
|
| 65 |
+
// Control whether or not we perform Async Error Handling with NCCL.
|
| 66 |
+
static std::vector<std::string> TORCH_NCCL_ASYNC_ERROR_HANDLING = {
|
| 67 |
+
"TORCH_NCCL_ASYNC_ERROR_HANDLING",
|
| 68 |
+
"NCCL_ASYNC_ERROR_HANDLING"};
|
| 69 |
+
|
| 70 |
+
// Control whether dumping debug info on watchdog
|
| 71 |
+
// timeout is enabled. This variable must be set together with
|
| 72 |
+
// TORCH_NCCL_ENABLE_MONITORING=1 and TORCH_NCCL_TRACE_BUFFER_SIZE > 0.
|
| 73 |
+
static std::vector<std::string> TORCH_NCCL_DUMP_ON_TIMEOUT = {
|
| 74 |
+
"TORCH_NCCL_DUMP_ON_TIMEOUT"};
|
| 75 |
+
|
| 76 |
+
// Control whether to propagate NCCL errors to all ranks through TCPStore.
|
| 77 |
+
static std::vector<std::string> TORCH_NCCL_PROPAGATE_ERROR = {
|
| 78 |
+
"TORCH_NCCL_PROPAGATE_ERROR"};
|
| 79 |
+
|
| 80 |
+
// Control whether Desync Debug is enabled. This variable must be set
|
| 81 |
+
// together with TORCH_NCCL_ASYNC_ERROR_HANDLING.
|
| 82 |
+
static std::vector<std::string> TORCH_NCCL_DESYNC_DEBUG = {
|
| 83 |
+
"TORCH_NCCL_DESYNC_DEBUG",
|
| 84 |
+
"NCCL_DESYNC_DEBUG"};
|
| 85 |
+
|
| 86 |
+
// Enable recording start-events for all ProcessGroupNCCL collectives, and
|
| 87 |
+
// compute accurate collective timing per-collective. (Note: end-events are
|
| 88 |
+
// recorded by default. Turn on this flag can increase chances of a watchdog
|
| 89 |
+
// hang due to performing a CUDA event query which eventually calls
|
| 90 |
+
// cudaEventElapsedTime() API.
|
| 91 |
+
static std::vector<std::string> TORCH_NCCL_ENABLE_TIMING = {
|
| 92 |
+
"TORCH_NCCL_ENABLE_TIMING",
|
| 93 |
+
"NCCL_ENABLE_TIMING"};
|
| 94 |
+
|
| 95 |
+
// Enable monitoring thread which aborts the process when the ProcessGroupNCCL
|
| 96 |
+
// Watchdog thread gets stuck and no heartbeat is detected after
|
| 97 |
+
// TORCH_NCCL_HEARTBEAT_TIMEOUT_SEC. This can happen due to calling CUDA/NCCL
|
| 98 |
+
// APIs that may hang. It is Useful to prevent jobs being stuck for a prolonged
|
| 99 |
+
// time than necessary tying up cluster resources.
|
| 100 |
+
static std::vector<std::string> TORCH_NCCL_ENABLE_MONITORING = {
|
| 101 |
+
"TORCH_NCCL_ENABLE_MONITORING"};
|
| 102 |
+
|
| 103 |
+
// Control the watchdog heartbeat timeout period after which the monitoring
|
| 104 |
+
// thread will abort the process.
|
| 105 |
+
static std::vector<std::string> TORCH_NCCL_HEARTBEAT_TIMEOUT_SEC = {
|
| 106 |
+
"TORCH_NCCL_HEARTBEAT_TIMEOUT_SEC"};
|
| 107 |
+
|
| 108 |
+
// Whether to rethrow CUDA Errors in the watchdog (default true)
|
| 109 |
+
static std::vector<std::string> TORCH_NCCL_RETHROW_CUDA_ERRORS = {
|
| 110 |
+
"TORCH_NCCL_RETHROW_CUDA_ERRORS"};
|
| 111 |
+
|
| 112 |
+
// The maximum number of events we store in the flight recorder's ring buffer.
|
| 113 |
+
// (One event could be the start or end of a collective, for example).
|
| 114 |
+
static std::vector<std::string> TORCH_NCCL_TRACE_BUFFER_SIZE = {
|
| 115 |
+
"TORCH_NCCL_TRACE_BUFFER_SIZE"};
|
| 116 |
+
|
| 117 |
+
// Control how much extra time we will wait for dumping the debugging info
|
| 118 |
+
// before we exit and throws timeout exception.
|
| 119 |
+
static std::vector<std::string> TORCH_NCCL_WAIT_TIMEOUT_DUMP_MILSEC = {
|
| 120 |
+
"TORCH_NCCL_WAIT_TIMEOUT_DUMP_MILSEC"};
|
| 121 |
+
|
| 122 |
+
// Control the interval inside the monitoring thread to check the coordinated
|
| 123 |
+
// signal from other ranks, e.g. to dump the debugging information.
|
| 124 |
+
static std::vector<std::string> TORCH_NCCL_COORD_CHECK_MILSEC = {
|
| 125 |
+
"TORCH_NCCL_COORD_CHECK_MILSEC"};
|
| 126 |
+
|
| 127 |
+
// Whether to log C++ stack traces on unclean shutdown (default true)
|
| 128 |
+
static std::vector<std::string> TORCH_NCCL_LOG_CPP_STACK_ON_UNCLEAN_SHUTDOWN = {
|
| 129 |
+
"TORCH_NCCL_LOG_CPP_STACK_ON_UNCLEAN_SHUTDOWN"};
|
| 130 |
+
|
| 131 |
+
// Whether to include only active collectives in the Flight Recorder trace
|
| 132 |
+
// (default false)
|
| 133 |
+
static std::vector<std::string> TORCH_NCCL_EXTRA_DUMP_ON_EXEC = {
|
| 134 |
+
"TORCH_NCCL_EXTRA_DUMP_ON_EXEC"};
|
| 135 |
+
|
| 136 |
+
// Control whether to use CudaEventCache for the collective in watchdog thread.
|
| 137 |
+
// We noticed in the past when cuda global lock is held, destroying CudaEvent
|
| 138 |
+
// can cause a hang.
|
| 139 |
+
static std::vector<std::string> TORCH_NCCL_CUDA_EVENT_CACHE = {
|
| 140 |
+
"TORCH_NCCL_CUDA_EVENT_CACHE"};
|
| 141 |
+
|
| 142 |
+
// Control the number of ranks each root can cover during NCCL comm init.
|
| 143 |
+
static std::vector<std::string> TORCH_NCCL_RANKS_PER_ROOT = {
|
| 144 |
+
"TORCH_NCCL_RANKS_PER_ROOT"};
|
| 145 |
+
|
| 146 |
+
static std::vector<std::string> TORCH_NCCL_NAN_CHECK = {"TORCH_NCCL_NAN_CHECK"};
|
| 147 |
+
|
| 148 |
+
constexpr const char* NCCL_BACKEND_NAME = "nccl";
|
| 149 |
+
|
| 150 |
+
constexpr const char* kStoreDumpKey = "exception_dump";
|
| 151 |
+
|
| 152 |
+
constexpr const char* kStoreErrorSignalKey = "remote_error";
|
| 153 |
+
|
| 154 |
+
constexpr const int kWorkStatusUpdatePeriodMs = 30 * 1000; // 30 seconds
|
| 155 |
+
|
| 156 |
+
constexpr auto kProcessGroupNCCLDefaultTimeout =
|
| 157 |
+
std::chrono::milliseconds(10 * 60 * 1000);
|
| 158 |
+
|
| 159 |
+
// NoHandling: do not handle asynchronous NCCL errors
|
| 160 |
+
// TearDown: tear down process upon error, see `WorkNCCL::handleException`
|
| 161 |
+
// CleanUpOnly: just clean up collectives and abort communicators without
|
| 162 |
+
// tearing down process SkipCleanUp: (this is a temporary option and can be
|
| 163 |
+
// removed in future) tear down process without cleaning up NCCL communicators.
|
| 164 |
+
// This should be used as a last resort in case `ncclCommAbort` itself is
|
| 165 |
+
// hanging
|
| 166 |
+
enum ErrorHandlingMode {
|
| 167 |
+
NoHandling = 0,
|
| 168 |
+
TearDown = 1,
|
| 169 |
+
CleanUpOnly = 2,
|
| 170 |
+
SkipCleanUp = 3
|
| 171 |
+
};
|
| 172 |
+
|
| 173 |
+
#define SHOULD_CLEAN_UP(a) (a != NoHandling && a != SkipCleanUp)
|
| 174 |
+
|
| 175 |
+
#define SHOULD_TEAR_DOWN(a) (a != NoHandling && a != CleanUpOnly)
|
| 176 |
+
|
| 177 |
+
#define PRINT_COLLECTIVE_HASH_SIGNATURE(phase, opType, numel, hashValue) \
|
| 178 |
+
LOG(WARNING) << logPrefix() << "Hash of " << phase << " to NCCL " << opType \
|
| 179 |
+
<< " with size " << numel << " is " << hashValue;
|
| 180 |
+
|
| 181 |
+
// If set, ProcessGroupNCCL doesn't use recordStream calls to ensure
|
| 182 |
+
// caching allocator safety for tensors used on both user-facing and
|
| 183 |
+
// internal comm streams.
|
| 184 |
+
// Instead, it stashes live references to those tensors until after
|
| 185 |
+
// user-facing streams are synced with comm streams.
|
| 186 |
+
// See stashed_for_allocator_safety_ below.
|
| 187 |
+
static std::vector<std::string> TORCH_NCCL_AVOID_RECORD_STREAMS = {
|
| 188 |
+
"TORCH_NCCL_AVOID_RECORD_STREAMS"};
|
| 189 |
+
|
| 190 |
+
// If set, ProcessGroupNCCL registers postAlloc and preFree hooks to cuda cache
|
| 191 |
+
// allocator so that whenever a tensor is allocated or freed, ProcessGroupNCCL
|
| 192 |
+
// can register/deregister the tensor on all available NCCL communicators.
|
| 193 |
+
static std::vector<std::string> TORCH_NCCL_USE_TENSOR_REGISTER_ALLOCATOR_HOOK =
|
| 194 |
+
{"TORCH_NCCL_USE_TENSOR_REGISTER_ALLOCATOR_HOOK",
|
| 195 |
+
"NCCL_USE_TENSOR_REGISTER_ALLOCATOR_HOOK"};
|
| 196 |
+
|
| 197 |
+
#if defined(__linux__)
|
| 198 |
+
struct DumpPipe {
|
| 199 |
+
DumpPipe(int rank, const std::string& fileStem, int traceBufferSize) {
|
| 200 |
+
if (fileStem.empty() || traceBufferSize <= 0) {
|
| 201 |
+
return;
|
| 202 |
+
}
|
| 203 |
+
std::string filename = c10::str(fileStem, rank, ".pipe");
|
| 204 |
+
TORCH_CHECK(
|
| 205 |
+
unlink(filename.c_str()) != -1 || errno == ENOENT,
|
| 206 |
+
"Error removing existing named pipe ",
|
| 207 |
+
filename,
|
| 208 |
+
", Error: ",
|
| 209 |
+
std::strerror(errno));
|
| 210 |
+
TORCH_CHECK(
|
| 211 |
+
mkfifo(filename.c_str(), 0666) != -1,
|
| 212 |
+
"Error creating named pipe ",
|
| 213 |
+
filename,
|
| 214 |
+
", Error: ",
|
| 215 |
+
std::strerror(errno));
|
| 216 |
+
fd_ = open(filename.c_str(), O_RDONLY | O_NONBLOCK);
|
| 217 |
+
LOG(INFO) << "Pipe file " << filename
|
| 218 |
+
<< " has been opened, write to it to trigger NCCL Debug Dump.";
|
| 219 |
+
TORCH_CHECK(fd_ != -1, "Error opening named pipe ", filename);
|
| 220 |
+
}
|
| 221 |
+
bool shouldDump() {
|
| 222 |
+
if (fd_ == -1) {
|
| 223 |
+
return false;
|
| 224 |
+
}
|
| 225 |
+
// NOLINTNEXTLINE(*array*)
|
| 226 |
+
char buf[128]{};
|
| 227 |
+
// non-blocking from O_NONBLOCK above.
|
| 228 |
+
// Ignore EINTR because we already will poll this
|
| 229 |
+
// again later.
|
| 230 |
+
ssize_t bytesRead = read(fd_, &buf, 128);
|
| 231 |
+
return bytesRead > 0;
|
| 232 |
+
}
|
| 233 |
+
~DumpPipe() {
|
| 234 |
+
if (fd_ != -1) {
|
| 235 |
+
close(fd_);
|
| 236 |
+
}
|
| 237 |
+
}
|
| 238 |
+
|
| 239 |
+
private:
|
| 240 |
+
int fd_ = -1;
|
| 241 |
+
};
|
| 242 |
+
#else
|
| 243 |
+
struct DumpPipe {
|
| 244 |
+
DumpPipe(int rank) {}
|
| 245 |
+
bool shouldDump() {
|
| 246 |
+
return false;
|
| 247 |
+
}
|
| 248 |
+
};
|
| 249 |
+
#endif
|
| 250 |
+
|
| 251 |
+
// A shelf for stashing tensors between op call and `work.wait()`.
|
| 252 |
+
// Used in case of async ops.
|
| 253 |
+
class TensorShelf {
|
| 254 |
+
public:
|
| 255 |
+
// Stash tensors so that CachingAllocator cannot recycle them prematurely.
|
| 256 |
+
void stash(std::vector<at::Tensor>& tensors);
|
| 257 |
+
// Stash tensors from another shelf.
|
| 258 |
+
void stash(TensorShelf& other);
|
| 259 |
+
// Unstage the stashed tensors so that CachingAllocator can recycle them.
|
| 260 |
+
// Same as `clear()`.
|
| 261 |
+
void unstash();
|
| 262 |
+
// Whether shelf is empty.
|
| 263 |
+
bool empty();
|
| 264 |
+
// Clear the shelf.
|
| 265 |
+
void clear();
|
| 266 |
+
|
| 267 |
+
protected:
|
| 268 |
+
// Get the inner tensor vector. Use with caution as it is not protected by
|
| 269 |
+
// mutex.
|
| 270 |
+
std::vector<at::Tensor>& get();
|
| 271 |
+
|
| 272 |
+
private:
|
| 273 |
+
std::vector<at::Tensor> tVector_;
|
| 274 |
+
// Need a mutex to protect `tVector_` because it can be potentially accessed
|
| 275 |
+
// from both main thread and watchdog thread.
|
| 276 |
+
std::mutex mutex_;
|
| 277 |
+
};
|
| 278 |
+
|
| 279 |
+
// ProcessGroupNCCL implements NCCL bindings for c10d.
|
| 280 |
+
//
|
| 281 |
+
// All functions of the class are expected to be called in the same order
|
| 282 |
+
// across all processes in the process group. This is the only way that we
|
| 283 |
+
// can guarantee to match up the same calls among all processes.
|
| 284 |
+
//
|
| 285 |
+
// All NCCL functions provided by this class are asynchronous functions. More
|
| 286 |
+
// specifically, each NCCL call is scheduled on a separate CUDA stream that is
|
| 287 |
+
// different from the current CUDA stream. This is for the purpose of
|
| 288 |
+
// achieving potentially concurrency and better performance. As a result,
|
| 289 |
+
// it is the callers' responsibility to make sure that the CUDA stream their
|
| 290 |
+
// code works on needs to wait for the NCCL operation from
|
| 291 |
+
// this class.
|
| 292 |
+
//
|
| 293 |
+
// This can be done by calling:
|
| 294 |
+
//
|
| 295 |
+
// either WorkNCCL::wait() or WorkNCCL::synchronize(), both achieves the same
|
| 296 |
+
// functionality and are synonyms.
|
| 297 |
+
//
|
| 298 |
+
// Also note that WorkNCCL::finishedGPUExecution() is a helper function only
|
| 299 |
+
// provided by ProcessGroupNCCL to check if the NCCL operation of WorkNCCL has
|
| 300 |
+
// finished execution on the GPU (not just scheduled).
|
| 301 |
+
//
|
| 302 |
+
// Example on using the NCCL process group
|
| 303 |
+
//
|
| 304 |
+
// ProcessGroupNCCL pg(store, rank, size);
|
| 305 |
+
// std::shared_ptr<WorkNCCL> work = pg.allreduce(tensors);
|
| 306 |
+
//
|
| 307 |
+
// // At this point, NCCL kernel has already by queued successfully
|
| 308 |
+
// // Now, let current stream wait for the NCCL to finish, this function is
|
| 309 |
+
// // async operation as well
|
| 310 |
+
//
|
| 311 |
+
// work->wait()
|
| 312 |
+
//
|
| 313 |
+
// // Now continue on other work in the current stream.
|
| 314 |
+
class TORCH_API ProcessGroupNCCL : public Backend {
|
| 315 |
+
public:
|
| 316 |
+
class WorkNCCL : public Work, public std::enable_shared_from_this<WorkNCCL> {
|
| 317 |
+
public:
|
| 318 |
+
friend struct WorkInfo;
|
| 319 |
+
|
| 320 |
+
// Constructor takes a list of CUDA devices
|
| 321 |
+
WorkNCCL(
|
| 322 |
+
std::string pgUID,
|
| 323 |
+
std::string pgDesc,
|
| 324 |
+
at::Device& device,
|
| 325 |
+
int rank,
|
| 326 |
+
OpType opType,
|
| 327 |
+
uint64_t seq,
|
| 328 |
+
bool isP2P = false,
|
| 329 |
+
const char* profilingTitle = nullptr,
|
| 330 |
+
const std::optional<std::vector<at::Tensor>>& inputs = std::nullopt,
|
| 331 |
+
bool enableTiming = false,
|
| 332 |
+
bool cudaEventCacheEnabled = false,
|
| 333 |
+
DebugLevel distDebugLevel = DebugLevel::Off);
|
| 334 |
+
// Copy constructor doing partial copy without outputs_. Cleanup thread
|
| 335 |
+
// monitors and removes finished works. However it will deadlock when
|
| 336 |
+
// destructs outputs_ tensors who are view tensors in autograd graph.
|
| 337 |
+
WorkNCCL(const WorkNCCL& w);
|
| 338 |
+
|
| 339 |
+
~WorkNCCL() override = default;
|
| 340 |
+
|
| 341 |
+
// Checks if the NCCL kernel has started to execute.
|
| 342 |
+
bool isStarted();
|
| 343 |
+
|
| 344 |
+
// Checks if request has completed. In this specific case of NCCL, it checks
|
| 345 |
+
// if the NCCL operation has completed on the GPU in its own NCCL stream.
|
| 346 |
+
// Non-blocking operation.
|
| 347 |
+
bool isCompleted() override;
|
| 348 |
+
|
| 349 |
+
bool isSuccess() const override;
|
| 350 |
+
|
| 351 |
+
// Same as calling synchronize() for NCCL work if timeout is not set.
|
| 352 |
+
// Otherwise, it will block the CPU thread until the NCCL work is completed
|
| 353 |
+
// or timed out. If timeout, exception will be thrown.
|
| 354 |
+
bool wait(std::chrono::milliseconds timeout = kNoTimeout) override;
|
| 355 |
+
|
| 356 |
+
void blockCurrentStream() override {
|
| 357 |
+
synchronize();
|
| 358 |
+
}
|
| 359 |
+
|
| 360 |
+
void abort() override;
|
| 361 |
+
|
| 362 |
+
// Let current stream wait on the completion of the NCCL work
|
| 363 |
+
// Throws on exceptions.
|
| 364 |
+
void synchronize() override;
|
| 365 |
+
|
| 366 |
+
// Synchronize streams by blocking each on the NCCL stream
|
| 367 |
+
void synchronizeStream();
|
| 368 |
+
|
| 369 |
+
// Helper function to handle exception (throw if needed).
|
| 370 |
+
void handleException(ErrorHandlingMode asyncErrorHandling);
|
| 371 |
+
|
| 372 |
+
// Helper function that checks if the NCCL kernels have finished
|
| 373 |
+
// execution on the GPUs
|
| 374 |
+
bool finishedGPUExecution();
|
| 375 |
+
|
| 376 |
+
// Get a Future object that will be marked as completed internally.
|
| 377 |
+
c10::intrusive_ptr<c10::ivalue::Future> getFuture() override;
|
| 378 |
+
|
| 379 |
+
// Get a Future result of each work (e.g. success, different error types).
|
| 380 |
+
// instead of the tensor output.
|
| 381 |
+
c10::intrusive_ptr<c10::ivalue::Future> getFutureResult() override;
|
| 382 |
+
|
| 383 |
+
float getDuration() const override;
|
| 384 |
+
|
| 385 |
+
uint64_t getSequencenumber() const override;
|
| 386 |
+
|
| 387 |
+
const std::string& logPrefix() const;
|
| 388 |
+
|
| 389 |
+
// Helper function that sets an exception_ptr on the WorkNCCL object.
|
| 390 |
+
void setException(std::exception_ptr exception_ptr);
|
| 391 |
+
|
| 392 |
+
// Helper function that returns True if the WorkNCCL object has timed out
|
| 393 |
+
// and False otherwise.
|
| 394 |
+
// In case of timeout, set exception on the WorkNCCL object.
|
| 395 |
+
bool checkTimeout(
|
| 396 |
+
std::optional<std::chrono::milliseconds> timeout = std::nullopt);
|
| 397 |
+
|
| 398 |
+
// Print the traceback of the collective at call time
|
| 399 |
+
void printTraceback() const;
|
| 400 |
+
|
| 401 |
+
std::string getTraceback() const;
|
| 402 |
+
|
| 403 |
+
std::vector<at::Tensor> result() override;
|
| 404 |
+
|
| 405 |
+
protected:
|
| 406 |
+
// The process group unique id
|
| 407 |
+
std::string pgUID_;
|
| 408 |
+
|
| 409 |
+
// The process group description
|
| 410 |
+
std::string pgDesc_;
|
| 411 |
+
|
| 412 |
+
// The cached list of CUDA devices to operate on
|
| 413 |
+
at::Device device_;
|
| 414 |
+
|
| 415 |
+
// The start CUDA event of NCCL operator tracking this work item. These
|
| 416 |
+
// start CUDA events are needed by desync debugging if enabled.
|
| 417 |
+
std::shared_ptr<at::cuda::CUDAEvent> ncclStartEvent_;
|
| 418 |
+
|
| 419 |
+
// The end CUDA event of NCCL operator tracking this work item.
|
| 420 |
+
std::shared_ptr<at::cuda::CUDAEvent> ncclEndEvent_;
|
| 421 |
+
|
| 422 |
+
// The NCCL communicator used for this work item.
|
| 423 |
+
std::shared_ptr<NCCLComm> ncclComm_;
|
| 424 |
+
|
| 425 |
+
// whether this work is a barrier op
|
| 426 |
+
bool isBarrierOp_{false};
|
| 427 |
+
|
| 428 |
+
// Clone of blockingWait_ from ProcessGroupNCCL.
|
| 429 |
+
bool blockingWait_{false};
|
| 430 |
+
|
| 431 |
+
// Clone of opTimeout_ from ProcessGroupNCCL.
|
| 432 |
+
std::chrono::milliseconds opTimeout_{};
|
| 433 |
+
|
| 434 |
+
// Ephemeral timeouts are owned by exactly one work,
|
| 435 |
+
// and reset after that work completes.
|
| 436 |
+
// There may be more than one ephemeral timeout active at the same time,
|
| 437 |
+
// and this variable is used to track the ownership of ephemeral timeout.
|
| 438 |
+
std::chrono::milliseconds ownedEphermeralTimeout_ =
|
| 439 |
+
std::chrono::milliseconds(0);
|
| 440 |
+
|
| 441 |
+
// Time point representing when the work started.
|
| 442 |
+
std::chrono::time_point<std::chrono::steady_clock> workStartTime_;
|
| 443 |
+
|
| 444 |
+
// Record the sequential number of collective or p2p.
|
| 445 |
+
uint64_t seq_;
|
| 446 |
+
bool isP2P_;
|
| 447 |
+
|
| 448 |
+
// Indicates if the nccl start event has been updated to the store trace.
|
| 449 |
+
// This will be used by desync debug.
|
| 450 |
+
bool startTraceUpdated_{false};
|
| 451 |
+
|
| 452 |
+
// Record collective sizes for debug. We only record the size on the first
|
| 453 |
+
// device as multi-device per process is deprecated
|
| 454 |
+
size_t numelIn_ = 0;
|
| 455 |
+
size_t numelOut_ = 0;
|
| 456 |
+
|
| 457 |
+
// Wrapper method for the static checkForNCCLErrors which can be overridden
|
| 458 |
+
// for tests.
|
| 459 |
+
virtual std::exception_ptr checkForNCCLErrors();
|
| 460 |
+
|
| 461 |
+
friend std::ostream& operator<<(
|
| 462 |
+
std::ostream& output,
|
| 463 |
+
const WorkNCCL& workNCCL);
|
| 464 |
+
|
| 465 |
+
// Checks for NCCL errors and sets an appropriate exception_ptr.
|
| 466 |
+
void checkAndSetException();
|
| 467 |
+
|
| 468 |
+
// Just checks whether GPU execution has started, without modifying
|
| 469 |
+
// exception_ptr.
|
| 470 |
+
bool startedGPUExecutionInternal() const;
|
| 471 |
+
|
| 472 |
+
// Just checks whether GPU execution has completed, without modifying
|
| 473 |
+
// exception_ptr.
|
| 474 |
+
bool finishedGPUExecutionInternal() const;
|
| 475 |
+
|
| 476 |
+
// Reference to the store so that we can write aborted communicators
|
| 477 |
+
// to the store.
|
| 478 |
+
c10::intrusive_ptr<Store> store_;
|
| 479 |
+
|
| 480 |
+
// Store a reference to NCCL collective's outputs, used by result and to
|
| 481 |
+
// give a more descriptive message when representing the Work as a string.
|
| 482 |
+
std::shared_ptr<std::vector<at::Tensor>> outputs_;
|
| 483 |
+
|
| 484 |
+
// TORCH_NCCL_AVOID_RECORD_STREAMS implementation helper.
|
| 485 |
+
// Stores references to participating non-output tensors (ie inputs,
|
| 486 |
+
// flattened intermediates).
|
| 487 |
+
// We'll clear this list in synchronizeStream, just after user-facing
|
| 488 |
+
// stream(s) are synced with the nccl work stream(s).
|
| 489 |
+
// By keeping these refs (as well as outputs_) alive until after the
|
| 490 |
+
// collective's work rejoins the user-facing streams, we achieve
|
| 491 |
+
// caching allocator safety without any recordStream calls.
|
| 492 |
+
// For in-place collectives, some refs stashed here may alias outputs_,
|
| 493 |
+
// but that doesn't do any harm.
|
| 494 |
+
std::shared_ptr<TensorShelf> stashed_for_allocator_safety_;
|
| 495 |
+
|
| 496 |
+
// The future returned by getFuture.
|
| 497 |
+
c10::intrusive_ptr<at::ivalue::Future> future_;
|
| 498 |
+
|
| 499 |
+
// the future result (e.g., success or failure) of the work
|
| 500 |
+
c10::intrusive_ptr<at::ivalue::Future> futureWorkResult_;
|
| 501 |
+
|
| 502 |
+
bool timingEnabled_;
|
| 503 |
+
// unique id used to tell the trace buffer that this
|
| 504 |
+
// work has completed
|
| 505 |
+
std::optional<uint64_t> trace_id_;
|
| 506 |
+
std::optional<uint64_t> trace_reset_epoch_;
|
| 507 |
+
DebugLevel distDebugLevel_;
|
| 508 |
+
friend class ProcessGroupNCCL;
|
| 509 |
+
};
|
| 510 |
+
|
| 511 |
+
struct Options : Backend::Options {
|
| 512 |
+
// NOTE: timeout in ProcessGroupNCCL::Options denote the timeout for
|
| 513 |
+
// operations. This is only used when blockingWait_ is enabled.
|
| 514 |
+
explicit Options(bool is_high_priority_stream = false);
|
| 515 |
+
Options(const Options&) = default;
|
| 516 |
+
Options(Options&&) noexcept = default;
|
| 517 |
+
Options& operator=(const Options&) = delete;
|
| 518 |
+
Options& operator=(Options&&) noexcept = delete;
|
| 519 |
+
~Options() override = default;
|
| 520 |
+
|
| 521 |
+
// return intrusive_ptr of the object
|
| 522 |
+
static c10::intrusive_ptr<Options> create(
|
| 523 |
+
bool is_high_priority_stream = false) {
|
| 524 |
+
return c10::make_intrusive<Options>(is_high_priority_stream);
|
| 525 |
+
}
|
| 526 |
+
|
| 527 |
+
// Schedule NCCL operations on high priority CUDA streams
|
| 528 |
+
bool is_high_priority_stream;
|
| 529 |
+
|
| 530 |
+
#ifdef NCCL_HAS_CONFIG
|
| 531 |
+
// Configure ranks
|
| 532 |
+
ncclConfig_t config = NCCL_CONFIG_INITIALIZER;
|
| 533 |
+
#endif
|
| 534 |
+
|
| 535 |
+
// Optional "parent" backend and color to create communicators from
|
| 536 |
+
// via `ncclCommSplit`
|
| 537 |
+
c10::intrusive_ptr<ProcessGroupNCCL> split_from;
|
| 538 |
+
// Color to use for `ncclCommSplit`, values:
|
| 539 |
+
// * Non-negative value: in group;
|
| 540 |
+
// * NCCL_SPLIT_NOCOLOR (-1): not in group;
|
| 541 |
+
// * NCCL_SPLIT_NOCOLOR - 1: uninitialized.
|
| 542 |
+
// [Note 1]: the type must be `int` instead of `int64_t` because NCCL API
|
| 543 |
+
// accepts int. Otherwise, an implicit conversion may happen at the API call
|
| 544 |
+
// and the value may become negative.
|
| 545 |
+
// [Note 2]: this member is pybinded to Python, the value passed from Python
|
| 546 |
+
// must be within the numerical range of C++ int. Otherwise, Python will
|
| 547 |
+
// raise a RuntimeError saying type is incompatible. See also
|
| 548 |
+
// `_process_group_color` in `distributed_c10d.py`.
|
| 549 |
+
#ifdef NCCL_HAS_COMM_SPLIT
|
| 550 |
+
int split_color{NCCL_SPLIT_NOCOLOR - 1};
|
| 551 |
+
#else
|
| 552 |
+
// [Note 3]: for older NCCL versions, NCCL_SPLIT_NOCOLOR is not defined. But
|
| 553 |
+
// `split_color` is pybinded to Python, so we need to define it. So we use
|
| 554 |
+
// the int value of `NCCL_SPLIT_NOCOLOR` (-1) instead.
|
| 555 |
+
int split_color{-2};
|
| 556 |
+
#endif
|
| 557 |
+
};
|
| 558 |
+
|
| 559 |
+
// Helper class related to TORCH_NCCL_DESYNC_DEBUG
|
| 560 |
+
class DesyncDebugger {
|
| 561 |
+
public:
|
| 562 |
+
// Initialize and enable DesyncDebugger
|
| 563 |
+
void init(
|
| 564 |
+
int rank,
|
| 565 |
+
int size,
|
| 566 |
+
int globalRank,
|
| 567 |
+
int pgId,
|
| 568 |
+
c10::intrusive_ptr<Store> store);
|
| 569 |
+
|
| 570 |
+
// Run desync debug. This function is called by watchdog at time of timeout.
|
| 571 |
+
void run();
|
| 572 |
+
|
| 573 |
+
// Log work start to store.
|
| 574 |
+
void logWorkStart(WorkNCCL& work);
|
| 575 |
+
|
| 576 |
+
// Log work end to store.
|
| 577 |
+
void logWorkEnd(WorkNCCL& work);
|
| 578 |
+
|
| 579 |
+
private:
|
| 580 |
+
// Whether desync debug is enabled.
|
| 581 |
+
// If false, all functions are no-op.
|
| 582 |
+
bool enabled_{false};
|
| 583 |
+
|
| 584 |
+
// From ProcessGroupNCCL
|
| 585 |
+
int rank_;
|
| 586 |
+
int size_;
|
| 587 |
+
int globalRank_;
|
| 588 |
+
int pgId_;
|
| 589 |
+
|
| 590 |
+
// Reference to the store so that we can log start/end event.
|
| 591 |
+
c10::intrusive_ptr<Store> store_;
|
| 592 |
+
|
| 593 |
+
// The store keys to trace the last NCCL collective kernel CUDA events -
|
| 594 |
+
// start event and end event respectively. These are used to do desync root
|
| 595 |
+
// cause analysis.
|
| 596 |
+
std::string traceKeyStart_;
|
| 597 |
+
std::string traceKeyEnd_;
|
| 598 |
+
};
|
| 599 |
+
|
| 600 |
+
// Class that runs as a separate thread aside from watchdog
|
| 601 |
+
// thread because we need to check the heartbeat from watchdog thread
|
| 602 |
+
// so that when we get stuck in some NCCL/CUDA calls,
|
| 603 |
+
// we can dump the debugging information and abort the process.
|
| 604 |
+
class HeartbeatMonitor {
|
| 605 |
+
public:
|
| 606 |
+
HeartbeatMonitor(ProcessGroupNCCL* pg);
|
| 607 |
+
virtual ~HeartbeatMonitor() = default;
|
| 608 |
+
|
| 609 |
+
// Start the heartbeat monitor thread.
|
| 610 |
+
void start();
|
| 611 |
+
|
| 612 |
+
// Join the heartbeat monitor thread.
|
| 613 |
+
void join();
|
| 614 |
+
|
| 615 |
+
// Run the actual loop to check watchdog heartbeat.
|
| 616 |
+
virtual void runLoop();
|
| 617 |
+
|
| 618 |
+
// Set the terminal flag and notify the heartbeat monitor thread to stop.
|
| 619 |
+
void stop();
|
| 620 |
+
|
| 621 |
+
// Set the last update time of watchdog thread.
|
| 622 |
+
void setLastWorkListUpdateTime(
|
| 623 |
+
std::chrono::time_point<std::chrono::steady_clock> time);
|
| 624 |
+
|
| 625 |
+
int getDumpTimeout() const;
|
| 626 |
+
|
| 627 |
+
// Util function to get the timeout error message
|
| 628 |
+
std::string getNCCLWatchdogTimeoutErrorMsg(const std::string& extraMsg);
|
| 629 |
+
|
| 630 |
+
// Util function to get the timeout exit message
|
| 631 |
+
std::string getNCCLWatchdogTimeoutExitMsg(const std::string& exitReason);
|
| 632 |
+
|
| 633 |
+
protected:
|
| 634 |
+
// We need to keep a reference to the PG instance so that we can access
|
| 635 |
+
// the member functions of the PG instance. We store a raw pointer on
|
| 636 |
+
// purpose because the heartbeat monitor thread now still lives within the
|
| 637 |
+
// lifetime of the PG instance.
|
| 638 |
+
ProcessGroupNCCL* pg_;
|
| 639 |
+
|
| 640 |
+
private:
|
| 641 |
+
// Whether or not to print C++ stack traces to logs on unclean shutdown.
|
| 642 |
+
bool logCppStackOnUncleanShutdown_;
|
| 643 |
+
|
| 644 |
+
// The time interval used for deciding whether there is no watchdog
|
| 645 |
+
// heartbeat.
|
| 646 |
+
int heartbeatTimeoutInSec_;
|
| 647 |
+
|
| 648 |
+
// timeout for the dump to finish.
|
| 649 |
+
int waitTimeoutDumpInMilSec_;
|
| 650 |
+
|
| 651 |
+
// Interval of check coordinated signals in ProcessGroupNCCL from other
|
| 652 |
+
// ranks e.g., trigger the dump of the debugging info for timeout when
|
| 653 |
+
// notified.
|
| 654 |
+
int coordCheckIntervalMilSec_;
|
| 655 |
+
|
| 656 |
+
// We gate the heartbeat monitor thread so that we can roll it out
|
| 657 |
+
// gradually.
|
| 658 |
+
bool watchdogHeartbeatMonitorEnabled_;
|
| 659 |
+
|
| 660 |
+
// Monitor thread which checks the heartbeat of Watchdog thread.
|
| 661 |
+
// If the monitor thread finds there is no heartbeat, it will dump debug
|
| 662 |
+
// info and then kill the watchdog thread to avoid hang.
|
| 663 |
+
std::thread ncclHeartbeatMonitorThread_;
|
| 664 |
+
|
| 665 |
+
// Whether or not we should terminate the heartbeat monitoring threads.
|
| 666 |
+
std::atomic<bool> terminateHeartbeatMonitorThread_{false};
|
| 667 |
+
|
| 668 |
+
// Condition Variable for monitor thread to wake up early
|
| 669 |
+
std::condition_variable monitorWakeUpCV_;
|
| 670 |
+
|
| 671 |
+
// Whether or not to dump debug info on exception including both watchdog
|
| 672 |
+
// timeout and nccl errors.
|
| 673 |
+
bool dumpOnTimeoutOrEx_;
|
| 674 |
+
|
| 675 |
+
// Mutex to Guard monitorWakeUpCV_
|
| 676 |
+
std::mutex monitorMutex_;
|
| 677 |
+
|
| 678 |
+
// The last update time of WorkList inside watchdog thread.
|
| 679 |
+
std::chrono::time_point<std::chrono::steady_clock> lastWorkListUpdateTime_;
|
| 680 |
+
};
|
| 681 |
+
|
| 682 |
+
// Class that runs as a side thread to check whether the NCCL collective
|
| 683 |
+
// is timed out or errors on the cached NCCL communicators.
|
| 684 |
+
class Watchdog {
|
| 685 |
+
public:
|
| 686 |
+
Watchdog(ProcessGroupNCCL* pg);
|
| 687 |
+
virtual ~Watchdog() = default;
|
| 688 |
+
|
| 689 |
+
// Start the watchdog thread.
|
| 690 |
+
void start();
|
| 691 |
+
|
| 692 |
+
// Join the watchdog thread.
|
| 693 |
+
void join();
|
| 694 |
+
|
| 695 |
+
// Function that runs as part of a separate thread and checks for errors on
|
| 696 |
+
// NCCL communicators. We need a separate thread to check for NCCL errors
|
| 697 |
+
// since we can't rely on the user calling certain methods like wait(),
|
| 698 |
+
// isCompleted() etc. to detect and remediate errors. In addition to this,
|
| 699 |
+
// we need a mechanism to safely abort and remove NCCL communicators from
|
| 700 |
+
// our cache. This can be done cleanly by having a thread for the
|
| 701 |
+
// ProcessGroupNCCL class. Attempting to modify the communicator cache from
|
| 702 |
+
// the WorkNCCL class might run into issues with object lifetime since the
|
| 703 |
+
// ProcessGroupNCCL object might get destroyed before the WorkNCCL object.
|
| 704 |
+
void run();
|
| 705 |
+
|
| 706 |
+
// Watchdog's inside loop.
|
| 707 |
+
// Takes care of cleaning up completed work, and aborting upon failure or
|
| 708 |
+
// timeout.
|
| 709 |
+
void runLoop();
|
| 710 |
+
|
| 711 |
+
// Notify the loop inside watchdog.
|
| 712 |
+
void notify();
|
| 713 |
+
|
| 714 |
+
void checkAndSetRemoteError();
|
| 715 |
+
|
| 716 |
+
// A helper function to get the src rank of a signal from the Store. This is
|
| 717 |
+
// nonblocking function returning -1 if the signal is not available yet.
|
| 718 |
+
int getSignalSrcRank(
|
| 719 |
+
c10::intrusive_ptr<Store>& store,
|
| 720 |
+
const std::string& signal);
|
| 721 |
+
|
| 722 |
+
uint64_t getHeartbt() const;
|
| 723 |
+
|
| 724 |
+
void setDesyncDebug(bool desyncDebug);
|
| 725 |
+
|
| 726 |
+
private:
|
| 727 |
+
std::thread ncclCommWatchdogThread_;
|
| 728 |
+
|
| 729 |
+
// We need to keep a reference to the PG instance so that we can access
|
| 730 |
+
// the member functions of the PG instance. We store a raw pointer on
|
| 731 |
+
// purpose because the watchdog thread now still lives within the
|
| 732 |
+
// lifetime of the PG instance.
|
| 733 |
+
ProcessGroupNCCL* pg_;
|
| 734 |
+
|
| 735 |
+
// Whether the NCCL watchdog should rethrow CUDA errors.
|
| 736 |
+
bool rethrowCUDAErrors_ = false;
|
| 737 |
+
|
| 738 |
+
std::exception_ptr watchDogException_ = nullptr;
|
| 739 |
+
|
| 740 |
+
// Condition Variable for watchdog thread sleep
|
| 741 |
+
std::condition_variable workMetaListCV_;
|
| 742 |
+
|
| 743 |
+
// Heartbeat of watchdog thread.
|
| 744 |
+
std::atomic_uint64_t heartbeat_;
|
| 745 |
+
|
| 746 |
+
// Whether or not to propagate detected errors to all ranks in the same PG
|
| 747 |
+
// through TCPStore.
|
| 748 |
+
bool propagatePgError_;
|
| 749 |
+
|
| 750 |
+
// Whether or not to enable timeout root cause analysis.
|
| 751 |
+
bool desyncDebug_;
|
| 752 |
+
|
| 753 |
+
DesyncDebugger desyncDebugger_;
|
| 754 |
+
};
|
| 755 |
+
|
| 756 |
+
// If you wish to create multiple process groups, each with a potentially
|
| 757 |
+
// different rank and size, you can do so by passing a new store instance
|
| 758 |
+
// to each one. If you have only a single store object, you can
|
| 759 |
+
// use the `c10d::PrefixStore` to derive scoped instances.
|
| 760 |
+
// This is also what the Python API in torch.distributed does.
|
| 761 |
+
//
|
| 762 |
+
// The process group instance keeps a reference to the store because
|
| 763 |
+
// it may be used long after the constructor runs. In fact, the constructor
|
| 764 |
+
// doesn't create any NCCL communicators. A single NCCL communicator can
|
| 765 |
+
// only be used on a specific set of devices, and are therefore created
|
| 766 |
+
// on-demand when a collective runs. If another collective is executed later,
|
| 767 |
+
// against a different set of devices, the process group creates another NCCL
|
| 768 |
+
// communicator. These NCCL communicators are cached and reused if possible.
|
| 769 |
+
//
|
| 770 |
+
ProcessGroupNCCL(
|
| 771 |
+
c10::intrusive_ptr<Store> store,
|
| 772 |
+
int rank,
|
| 773 |
+
int size,
|
| 774 |
+
c10::intrusive_ptr<Options> options = Options::create());
|
| 775 |
+
|
| 776 |
+
// This constructor includes the deprecated `groupName` argument.
|
| 777 |
+
// If you have existing code that uses the `groupName`, you can replace
|
| 778 |
+
// it by specifying a `c10d::PrefixStore(groupName, store)` for store.
|
| 779 |
+
C10_DEPRECATED ProcessGroupNCCL(
|
| 780 |
+
const c10::intrusive_ptr<Store>& store,
|
| 781 |
+
int rank,
|
| 782 |
+
int size,
|
| 783 |
+
const std::string& groupName,
|
| 784 |
+
c10::intrusive_ptr<Options> options = Options::create())
|
| 785 |
+
: ProcessGroupNCCL(store, rank, size, std::move(options)) {}
|
| 786 |
+
|
| 787 |
+
~ProcessGroupNCCL() override;
|
| 788 |
+
|
| 789 |
+
// This function returns a local uid for ProcessGroupNCCL.
|
| 790 |
+
uint64_t getUid() {
|
| 791 |
+
return static_cast<uint64_t>(local_id_);
|
| 792 |
+
}
|
| 793 |
+
|
| 794 |
+
c10::intrusive_ptr<Options> getOptions() {
|
| 795 |
+
return options_;
|
| 796 |
+
}
|
| 797 |
+
|
| 798 |
+
c10::intrusive_ptr<Backend::Options> getBackendOptions() override {
|
| 799 |
+
return c10::static_intrusive_pointer_cast<Backend::Options>(options_);
|
| 800 |
+
}
|
| 801 |
+
|
| 802 |
+
const std::string getBackendName() const override {
|
| 803 |
+
return std::string(NCCL_BACKEND_NAME);
|
| 804 |
+
}
|
| 805 |
+
|
| 806 |
+
bool supportsSplitting() const override {
|
| 807 |
+
return true;
|
| 808 |
+
}
|
| 809 |
+
|
| 810 |
+
bool supportsCoalescing() const override {
|
| 811 |
+
return true;
|
| 812 |
+
}
|
| 813 |
+
|
| 814 |
+
bool supportsTimeEstimation() const override {
|
| 815 |
+
#ifdef NCCL_SIM_INFO_INITIALIZER
|
| 816 |
+
return true;
|
| 817 |
+
#else
|
| 818 |
+
return false;
|
| 819 |
+
#endif
|
| 820 |
+
}
|
| 821 |
+
|
| 822 |
+
void setTimeout(std::chrono::milliseconds timeout) override {
|
| 823 |
+
options_->timeout = timeout;
|
| 824 |
+
}
|
| 825 |
+
|
| 826 |
+
void startCoalescing() override;
|
| 827 |
+
|
| 828 |
+
c10::intrusive_ptr<Work> endCoalescing() override;
|
| 829 |
+
|
| 830 |
+
void startTimeEstimate();
|
| 831 |
+
|
| 832 |
+
float endTimeEstimate();
|
| 833 |
+
|
| 834 |
+
// For specifying a composite optype, such as ALLGATHER and REDUCE_SCATTER
|
| 835 |
+
c10::intrusive_ptr<Work> endCoalescing(OpType optype);
|
| 836 |
+
|
| 837 |
+
c10::intrusive_ptr<Work> broadcast(
|
| 838 |
+
std::vector<at::Tensor>& tensors,
|
| 839 |
+
const BroadcastOptions& opts = BroadcastOptions()) override;
|
| 840 |
+
|
| 841 |
+
c10::intrusive_ptr<Work> _broadcast_oop(
|
| 842 |
+
at::Tensor& outputTensors,
|
| 843 |
+
at::Tensor& inputTensors,
|
| 844 |
+
const BroadcastOptions& opts = BroadcastOptions());
|
| 845 |
+
|
| 846 |
+
c10::intrusive_ptr<Work> allreduce_sparse(
|
| 847 |
+
std::vector<at::Tensor>& tensors,
|
| 848 |
+
const AllreduceOptions& opts = AllreduceOptions()) override;
|
| 849 |
+
|
| 850 |
+
c10::intrusive_ptr<Work> allreduce(
|
| 851 |
+
std::vector<at::Tensor>& tensors,
|
| 852 |
+
const AllreduceOptions& opts = AllreduceOptions()) override;
|
| 853 |
+
|
| 854 |
+
c10::intrusive_ptr<Work> allreduce_coalesced(
|
| 855 |
+
std::vector<at::Tensor>& tensors,
|
| 856 |
+
const AllreduceCoalescedOptions& opts =
|
| 857 |
+
AllreduceCoalescedOptions()) override;
|
| 858 |
+
|
| 859 |
+
c10::intrusive_ptr<Work> reduce(
|
| 860 |
+
std::vector<at::Tensor>& tensors,
|
| 861 |
+
const ReduceOptions& opts = ReduceOptions()) override;
|
| 862 |
+
|
| 863 |
+
c10::intrusive_ptr<Work> _reduce_oop(
|
| 864 |
+
at::Tensor& outputTensors,
|
| 865 |
+
at::Tensor& inputTensors,
|
| 866 |
+
const ReduceOptions& opts = ReduceOptions());
|
| 867 |
+
|
| 868 |
+
c10::intrusive_ptr<Work> allgather(
|
| 869 |
+
std::vector<std::vector<at::Tensor>>& outputTensors,
|
| 870 |
+
std::vector<at::Tensor>& inputTensors,
|
| 871 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 872 |
+
|
| 873 |
+
c10::intrusive_ptr<Work> _allgather_base(
|
| 874 |
+
at::Tensor& outputbuffer,
|
| 875 |
+
at::Tensor& inputbuffer,
|
| 876 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 877 |
+
|
| 878 |
+
c10::intrusive_ptr<Work> allgather_coalesced(
|
| 879 |
+
std::vector<std::vector<at::Tensor>>& outputTensorLists,
|
| 880 |
+
std::vector<at::Tensor>& inputTensors,
|
| 881 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 882 |
+
|
| 883 |
+
c10::intrusive_ptr<Work> allgather_into_tensor_coalesced(
|
| 884 |
+
std::vector<at::Tensor>& outputs,
|
| 885 |
+
std::vector<at::Tensor>& inputs,
|
| 886 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 887 |
+
|
| 888 |
+
c10::intrusive_ptr<Work> reduce_scatter(
|
| 889 |
+
std::vector<at::Tensor>& outputTensors,
|
| 890 |
+
std::vector<std::vector<at::Tensor>>& inputTensors,
|
| 891 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override;
|
| 892 |
+
|
| 893 |
+
c10::intrusive_ptr<Work> _reduce_scatter_base(
|
| 894 |
+
at::Tensor& outputTensor,
|
| 895 |
+
at::Tensor& inputTensor,
|
| 896 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override;
|
| 897 |
+
|
| 898 |
+
c10::intrusive_ptr<Work> reduce_scatter_tensor_coalesced(
|
| 899 |
+
std::vector<at::Tensor>& outputs,
|
| 900 |
+
std::vector<at::Tensor>& inputs,
|
| 901 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override;
|
| 902 |
+
|
| 903 |
+
c10::intrusive_ptr<Work> barrier(
|
| 904 |
+
const BarrierOptions& opts = BarrierOptions()) override;
|
| 905 |
+
|
| 906 |
+
c10::intrusive_ptr<Work> alltoall_base(
|
| 907 |
+
at::Tensor& outputTensor,
|
| 908 |
+
at::Tensor& inputTensor,
|
| 909 |
+
std::vector<int64_t>& outputSplitSizes,
|
| 910 |
+
std::vector<int64_t>& inputSplitSizes,
|
| 911 |
+
const AllToAllOptions& opts = AllToAllOptions()) override;
|
| 912 |
+
|
| 913 |
+
c10::intrusive_ptr<Work> alltoall(
|
| 914 |
+
std::vector<at::Tensor>& outputTensors,
|
| 915 |
+
std::vector<at::Tensor>& inputTensors,
|
| 916 |
+
const AllToAllOptions& opts = AllToAllOptions()) override;
|
| 917 |
+
|
| 918 |
+
c10::intrusive_ptr<Work> send(
|
| 919 |
+
std::vector<at::Tensor>& tensors,
|
| 920 |
+
int dstRank,
|
| 921 |
+
int tag) override;
|
| 922 |
+
|
| 923 |
+
c10::intrusive_ptr<Work> recv(
|
| 924 |
+
std::vector<at::Tensor>& tensors,
|
| 925 |
+
int srcRank,
|
| 926 |
+
int tag) override;
|
| 927 |
+
|
| 928 |
+
int64_t getCommPtr();
|
| 929 |
+
|
| 930 |
+
void groupStart();
|
| 931 |
+
|
| 932 |
+
void groupEnd();
|
| 933 |
+
|
| 934 |
+
void groupEndNonblocking(const std::shared_ptr<NCCLComm>& comm);
|
| 935 |
+
|
| 936 |
+
c10::intrusive_ptr<Work> gather(
|
| 937 |
+
std::vector<std::vector<at::Tensor>>& outputTensors,
|
| 938 |
+
std::vector<at::Tensor>& inputTensors,
|
| 939 |
+
const GatherOptions& opts = GatherOptions()) override;
|
| 940 |
+
|
| 941 |
+
c10::intrusive_ptr<Work> scatter(
|
| 942 |
+
std::vector<at::Tensor>& outputTensors,
|
| 943 |
+
std::vector<std::vector<at::Tensor>>& inputTensors,
|
| 944 |
+
const ScatterOptions& opts = ScatterOptions()) override;
|
| 945 |
+
|
| 946 |
+
// Unsupported Ops
|
| 947 |
+
c10::intrusive_ptr<Work> recvAnysource(
|
| 948 |
+
std::vector<at::Tensor>& tensors,
|
| 949 |
+
int tag) override;
|
| 950 |
+
|
| 951 |
+
// Agrees on an initial sequence number for the whole group by having rank 0
|
| 952 |
+
// create it and broadcast it to other ranks using the store.
|
| 953 |
+
void setSequenceNumberForGroup() override;
|
| 954 |
+
|
| 955 |
+
// Retrieves the current sequence number for the whole group, which should be
|
| 956 |
+
// in sync. If the returned number is not consistent across the group, it
|
| 957 |
+
// may indicate that there is some sort of collective desynchronization.
|
| 958 |
+
uint64_t getSequenceNumberForGroup() override;
|
| 959 |
+
|
| 960 |
+
// Return the total number of splits the communicators held by this process
|
| 961 |
+
// group have performed. Counts ncclCommCreateFromRanks() for ncclx v2.21.5+
|
| 962 |
+
uint64_t getCommSplitCounter() const;
|
| 963 |
+
|
| 964 |
+
void registerOnCompletionHook(
|
| 965 |
+
std::function<void(std::shared_ptr<WorkInfo>)>&& hook) override;
|
| 966 |
+
void waitForPendingWorks() override;
|
| 967 |
+
|
| 968 |
+
void enableCollectivesTiming() override;
|
| 969 |
+
|
| 970 |
+
c10::intrusive_ptr<Backend> split(
|
| 971 |
+
const c10::intrusive_ptr<Store>& store,
|
| 972 |
+
const std::vector<int>& ranks,
|
| 973 |
+
const c10::intrusive_ptr<Backend::Options>& opts) override;
|
| 974 |
+
|
| 975 |
+
c10::intrusive_ptr<Backend> merge(
|
| 976 |
+
const c10::intrusive_ptr<Store>& store,
|
| 977 |
+
const c10::intrusive_ptr<Backend::Options>& opts,
|
| 978 |
+
const int& rank,
|
| 979 |
+
const int& size) override;
|
| 980 |
+
|
| 981 |
+
// Helper function for iteratively aborting communicators in the provided map
|
| 982 |
+
void abortCommsFromMap(
|
| 983 |
+
std::unordered_map<std::string, std::shared_ptr<NCCLComm>>& ncclCommsMap,
|
| 984 |
+
const std::optional<std::string>& abortReason);
|
| 985 |
+
|
| 986 |
+
c10::intrusive_ptr<intra_node_comm::IntraNodeComm> initIntraNodeComm();
|
| 987 |
+
|
| 988 |
+
// Destroy (shutdown) this backend -- normal exit.
|
| 989 |
+
void shutdown() override;
|
| 990 |
+
|
| 991 |
+
// Provides an API to abort the ProcessGroup (similar to ncclCommAbort)
|
| 992 |
+
// instead of relying on ProcessGroupNCCL destructor.
|
| 993 |
+
void abort() override;
|
| 994 |
+
|
| 995 |
+
void eagerConnectSingleDevice(at::Device device) override;
|
| 996 |
+
|
| 997 |
+
void performNocolorSplit(at::Device device);
|
| 998 |
+
|
| 999 |
+
// If all comms on this PG are fully initialized, return true.
|
| 1000 |
+
bool isInitialized();
|
| 1001 |
+
|
| 1002 |
+
ErrorType getError() override;
|
| 1003 |
+
|
| 1004 |
+
bool supportsShrinking() const override {
|
| 1005 |
+
#ifdef NCCL_HAS_COMM_SHRINK
|
| 1006 |
+
return true;
|
| 1007 |
+
#else
|
| 1008 |
+
return false;
|
| 1009 |
+
#endif
|
| 1010 |
+
}
|
| 1011 |
+
|
| 1012 |
+
// Backend-style shrink override that returns a Backend instance.
|
| 1013 |
+
c10::intrusive_ptr<Backend> shrink(
|
| 1014 |
+
const std::vector<int64_t>& ranks_to_exclude,
|
| 1015 |
+
int shrink_flags = 0,
|
| 1016 |
+
const c10::intrusive_ptr<Backend::Options>& opts_override =
|
| 1017 |
+
nullptr) override;
|
| 1018 |
+
|
| 1019 |
+
std::shared_ptr<c10::Allocator> getMemAllocator() override;
|
| 1020 |
+
|
| 1021 |
+
// Allocate tensor from communication-optimized memory pool
|
| 1022 |
+
at::Tensor allocateTensor(long size, at::TensorOptions options = {}) override;
|
| 1023 |
+
|
| 1024 |
+
// Whether tensor allocation from NCCL memory pool is supported
|
| 1025 |
+
bool supportsTensorAlloc(c10::DeviceIndex deviceIdx) override;
|
| 1026 |
+
|
| 1027 |
+
// Performs NCCL user buffer registration for all buffers in
|
| 1028 |
+
// the given MemPool
|
| 1029 |
+
void registerMemPool(at::cuda::MemPool* pool, bool symm = false);
|
| 1030 |
+
|
| 1031 |
+
// Performs NCCL user buffer de-registration for all buffers in
|
| 1032 |
+
// the given MemPool
|
| 1033 |
+
void deregisterMemPool(at::cuda::MemPool* pool);
|
| 1034 |
+
|
| 1035 |
+
// This method adds a temporary extension for the timeout period,
|
| 1036 |
+
// applying to all collectives between the calling of this API and
|
| 1037 |
+
// the completion of the first collective on the GPU. While this feature
|
| 1038 |
+
// provides flexibility in specific scenarios, it introduces statefulness
|
| 1039 |
+
// to timeout setting. Therefore, it is advisable to use this API sparingly
|
| 1040 |
+
// and consider alternative approaches, such as directly setting the timeout
|
| 1041 |
+
// or utilizing a barrier collective (one can set any timeout to the barrier),
|
| 1042 |
+
// whenever feasible.
|
| 1043 |
+
void addEphemeralTimeout(const std::chrono::milliseconds& timeout);
|
| 1044 |
+
|
| 1045 |
+
// This function is only intended for testing purposes because we don't
|
| 1046 |
+
// want to expose the `WorkNCCL` via pybind. It verifies whether the
|
| 1047 |
+
// `opTimeout_` of the provided WorkNCCL instance is the same as the specified
|
| 1048 |
+
// timeout.
|
| 1049 |
+
bool verifyWorkTimeoutForTest(
|
| 1050 |
+
const c10::intrusive_ptr<Work>& work,
|
| 1051 |
+
const std::chrono::milliseconds& timeout);
|
| 1052 |
+
|
| 1053 |
+
void setEnableNanCheck(bool enableNanCheck);
|
| 1054 |
+
|
| 1055 |
+
// APIs related to memory offload (require NCCL 2.29.7+ at runtime)
|
| 1056 |
+
void suspend() override;
|
| 1057 |
+
|
| 1058 |
+
void resume() override;
|
| 1059 |
+
|
| 1060 |
+
std::unordered_map<std::string, uint64_t> getMemoryStats() override;
|
| 1061 |
+
|
| 1062 |
+
protected:
|
| 1063 |
+
uint64_t getWatchdogHeartbt() const;
|
| 1064 |
+
|
| 1065 |
+
// Instance of the heartbeat monitor thread.
|
| 1066 |
+
std::unique_ptr<HeartbeatMonitor> heartbeatMonitor_;
|
| 1067 |
+
|
| 1068 |
+
// Instance of the watchdog thread.
|
| 1069 |
+
std::unique_ptr<Watchdog> watchdog_;
|
| 1070 |
+
|
| 1071 |
+
// Helper that broadcasts nccl unique ID to all ranks through the store
|
| 1072 |
+
void broadcastUniqueNCCLID(
|
| 1073 |
+
ncclUniqueId* ncclID,
|
| 1074 |
+
bool isSingleP2POp,
|
| 1075 |
+
const std::string& devicesKey,
|
| 1076 |
+
int p2pRank);
|
| 1077 |
+
|
| 1078 |
+
// Helper that allgathers nccl unique IDs to all ranks through the store
|
| 1079 |
+
void allgatherUniqueNCCLIDs(
|
| 1080 |
+
int rootIdx,
|
| 1081 |
+
ncclUniqueId* ncclID,
|
| 1082 |
+
std::vector<ncclUniqueId>& ncclIDs);
|
| 1083 |
+
|
| 1084 |
+
// Helper that looks up the cached NCCL communicators only
|
| 1085 |
+
std::shared_ptr<NCCLComm> getNCCLComm(const std::string& deviceKey);
|
| 1086 |
+
|
| 1087 |
+
std::shared_ptr<NCCLComm> initNCCLComm(
|
| 1088 |
+
const std::string& deviceKey,
|
| 1089 |
+
at::Device& device,
|
| 1090 |
+
OpType opType,
|
| 1091 |
+
int p2pRank = 0,
|
| 1092 |
+
bool isSendRecvSelf = false);
|
| 1093 |
+
|
| 1094 |
+
// Initialize device-specific state (comm, stream, event, bookkeeping) for a
|
| 1095 |
+
// given communicator on this process group instance.
|
| 1096 |
+
void initializeDeviceStateForComm(
|
| 1097 |
+
const at::Device& device,
|
| 1098 |
+
std::shared_ptr<NCCLComm> comm);
|
| 1099 |
+
|
| 1100 |
+
// Wrapper method which can be overridden for tests.
|
| 1101 |
+
virtual std::exception_ptr checkForNCCLErrors(
|
| 1102 |
+
std::shared_ptr<NCCLComm>& ncclComm);
|
| 1103 |
+
|
| 1104 |
+
// Ensure thaht if record is True, the work obj will be enqueued via
|
| 1105 |
+
// workEnqueue
|
| 1106 |
+
virtual c10::intrusive_ptr<ProcessGroupNCCL::WorkNCCL> initWork(
|
| 1107 |
+
at::Device& device,
|
| 1108 |
+
int rank,
|
| 1109 |
+
OpType opType,
|
| 1110 |
+
bool isP2P,
|
| 1111 |
+
const char* profilingTitle = nullptr,
|
| 1112 |
+
const std::vector<at::Tensor>& inputs = {},
|
| 1113 |
+
const std::vector<at::Tensor>& outputs = {},
|
| 1114 |
+
bool record = false);
|
| 1115 |
+
|
| 1116 |
+
// In the timeout case and we will dump debug info such as the NCCL flight
|
| 1117 |
+
// recorder to storage. Down the road, if we have more complicated or blocking
|
| 1118 |
+
// operations, we might need to use a side thread to do it.
|
| 1119 |
+
bool dumpDebuggingInfo(
|
| 1120 |
+
bool includeStackTrace = true,
|
| 1121 |
+
bool onlyActive = false);
|
| 1122 |
+
|
| 1123 |
+
void dumpExtraDebuggingInfo();
|
| 1124 |
+
|
| 1125 |
+
// Abort all communicators on this rank.
|
| 1126 |
+
bool abortComms(const std::optional<std::string>& abortReason = std::nullopt);
|
| 1127 |
+
|
| 1128 |
+
// A helper function to check if nonblocking API mode should be used.
|
| 1129 |
+
// Use this helper instead of directly checking `useNonblocking_` variable.
|
| 1130 |
+
bool useNonblocking();
|
| 1131 |
+
|
| 1132 |
+
protected:
|
| 1133 |
+
int globalRankStart_{};
|
| 1134 |
+
int globalRankStride_{};
|
| 1135 |
+
|
| 1136 |
+
private:
|
| 1137 |
+
bool eagerInit_{false};
|
| 1138 |
+
bool showSerializationWarning_{true};
|
| 1139 |
+
|
| 1140 |
+
// Helper that encapsulates work shared across all collective communication
|
| 1141 |
+
// primitives. The callbacks have the following signatures:
|
| 1142 |
+
//
|
| 1143 |
+
// ncclResult_t fn(at::Tensor& input, at::Tensor& output,
|
| 1144 |
+
// ncclComm_t, at::cuda::CUDAStream&);
|
| 1145 |
+
// void {pre,post}(std::vector<at::cuda::CUDAStream&>);
|
| 1146 |
+
template <typename Fn>
|
| 1147 |
+
c10::intrusive_ptr<Work> collective(
|
| 1148 |
+
at::Tensor& input,
|
| 1149 |
+
at::Tensor& output,
|
| 1150 |
+
Fn fn,
|
| 1151 |
+
OpType opType,
|
| 1152 |
+
bool asyncOp,
|
| 1153 |
+
const char* profilingTitle = nullptr,
|
| 1154 |
+
bool nanCheck = true);
|
| 1155 |
+
|
| 1156 |
+
template <typename Fn, typename PreProcess, typename PostProcess>
|
| 1157 |
+
c10::intrusive_ptr<Work> collective(
|
| 1158 |
+
at::Tensor& input,
|
| 1159 |
+
at::Tensor& output,
|
| 1160 |
+
Fn fn,
|
| 1161 |
+
PreProcess pre,
|
| 1162 |
+
PostProcess post,
|
| 1163 |
+
OpType opType,
|
| 1164 |
+
bool asyncOp,
|
| 1165 |
+
const char* profilingTitle = nullptr,
|
| 1166 |
+
bool nanCheck = true);
|
| 1167 |
+
|
| 1168 |
+
template <typename Fn, typename PreProcess, typename PostProcess>
|
| 1169 |
+
c10::intrusive_ptr<Work> collective(
|
| 1170 |
+
std::vector<at::Tensor>& inputs,
|
| 1171 |
+
std::vector<at::Tensor>& outputs,
|
| 1172 |
+
Fn fn,
|
| 1173 |
+
PreProcess pre,
|
| 1174 |
+
PostProcess post,
|
| 1175 |
+
OpType opType,
|
| 1176 |
+
bool asyncOp,
|
| 1177 |
+
const char* profilingTitle = nullptr,
|
| 1178 |
+
bool nanCheck = true);
|
| 1179 |
+
|
| 1180 |
+
template <typename Fn>
|
| 1181 |
+
c10::intrusive_ptr<Work> collectiveCoalesced(
|
| 1182 |
+
std::vector<at::Tensor>& input,
|
| 1183 |
+
std::vector<at::Tensor>& output,
|
| 1184 |
+
Fn fn,
|
| 1185 |
+
OpType opType,
|
| 1186 |
+
bool asyncOp,
|
| 1187 |
+
const char* profilingTitle = nullptr);
|
| 1188 |
+
|
| 1189 |
+
// Helper that encapsulates work shared across point-to-point communication
|
| 1190 |
+
// primitives. It is the same structure as the helper used for collective
|
| 1191 |
+
// communication primitives.
|
| 1192 |
+
template <typename Fn>
|
| 1193 |
+
c10::intrusive_ptr<Work> pointToPoint(
|
| 1194 |
+
at::Tensor& tensor,
|
| 1195 |
+
Fn fn,
|
| 1196 |
+
int peer,
|
| 1197 |
+
OpType opType,
|
| 1198 |
+
const char* profilingTitle = nullptr);
|
| 1199 |
+
|
| 1200 |
+
template <typename Fn, typename PreProcess, typename PostProcess>
|
| 1201 |
+
c10::intrusive_ptr<Work> pointToPoint(
|
| 1202 |
+
at::Tensor& tensor,
|
| 1203 |
+
Fn fn,
|
| 1204 |
+
int peer,
|
| 1205 |
+
OpType opType,
|
| 1206 |
+
PreProcess pre,
|
| 1207 |
+
PostProcess post,
|
| 1208 |
+
const char* profilingTitle);
|
| 1209 |
+
|
| 1210 |
+
c10::intrusive_ptr<Work> allreduce_impl(
|
| 1211 |
+
at::Tensor& tensor,
|
| 1212 |
+
const char* profilingTitle = "nccl:all_reduce",
|
| 1213 |
+
const AllreduceOptions& opts = AllreduceOptions());
|
| 1214 |
+
|
| 1215 |
+
// Checks for NCCL errors on each of the communicators and returns an
|
| 1216 |
+
// appropriate exception_ptr (nullptr if no errors).
|
| 1217 |
+
static std::exception_ptr checkForNCCLErrorsInternal(
|
| 1218 |
+
std::shared_ptr<NCCLComm>& ncclComm);
|
| 1219 |
+
|
| 1220 |
+
// Return the CUDA device most likely associated with this backend.
|
| 1221 |
+
// If we aren't bound to a specific device, there is no strict
|
| 1222 |
+
// guarantee that this heuristic is the correct assignment of ranks
|
| 1223 |
+
// to GPUs that Python layers use, but in practice it tends to be.
|
| 1224 |
+
// Fortunately we don't rely on this for correctness of any tensor
|
| 1225 |
+
// operations, just for ancillary uses like barriers.
|
| 1226 |
+
at::Device guessDeviceForRank() const;
|
| 1227 |
+
|
| 1228 |
+
// Destroys initialized NCCL communicators in devNCCLComMap_ given by input
|
| 1229 |
+
// key. Throws if there are no communicators to destroy. Also removes
|
| 1230 |
+
// communicators from the cache and clears used device indices.
|
| 1231 |
+
void destroyNCCLComms(const std::string& devNCCLCommMapKey);
|
| 1232 |
+
|
| 1233 |
+
void runHookLoop();
|
| 1234 |
+
|
| 1235 |
+
// Generates a prefix that is unique to this process group and rank, for
|
| 1236 |
+
// disambiguating logs
|
| 1237 |
+
std::string createLogPrefix() const;
|
| 1238 |
+
|
| 1239 |
+
// Returns the unique prefix created in createLogPrefix
|
| 1240 |
+
const std::string& logPrefix() const;
|
| 1241 |
+
|
| 1242 |
+
// Returns the global rank of the device. This function assumes that users
|
| 1243 |
+
// always create a default global process group(PG) which includes all
|
| 1244 |
+
// devices. It is called in the constructor of ProcessGroupNCCL, so it always
|
| 1245 |
+
// return the rank_ of the very first PG created, aka, default global PG.
|
| 1246 |
+
const int& globalRank() const;
|
| 1247 |
+
|
| 1248 |
+
const c10::intrusive_ptr<Store>& globalStore() const;
|
| 1249 |
+
|
| 1250 |
+
// Returns the global ranks of a PG.
|
| 1251 |
+
const std::vector<uint64_t>& groupRanks() const;
|
| 1252 |
+
|
| 1253 |
+
// Util function to assign timeout to each work.
|
| 1254 |
+
void assignTimeoutToWork(
|
| 1255 |
+
const c10::intrusive_ptr<ProcessGroupNCCL::WorkNCCL>& work,
|
| 1256 |
+
const c10::intrusive_ptr<Options>& option);
|
| 1257 |
+
|
| 1258 |
+
// Broadcast flight-recorder dump signal
|
| 1259 |
+
void broadcastDumpSignal();
|
| 1260 |
+
|
| 1261 |
+
// A helper function to broadcast a signal (key) from a src rank to all other
|
| 1262 |
+
// ranks using the specified store.
|
| 1263 |
+
void broadcastSignal(
|
| 1264 |
+
c10::intrusive_ptr<Store>& store,
|
| 1265 |
+
const std::string& signal,
|
| 1266 |
+
int srcRank);
|
| 1267 |
+
|
| 1268 |
+
protected:
|
| 1269 |
+
// Function that directly trigger std::abort so that the whole process
|
| 1270 |
+
// gets terminated.
|
| 1271 |
+
virtual void terminateProcess(const std::string& errMsg);
|
| 1272 |
+
|
| 1273 |
+
// A helper function to wait for a future to complete or timeout.
|
| 1274 |
+
// Returns true if the future completes before timeout, false otherwise.
|
| 1275 |
+
bool waitForFutureOrTimeout(
|
| 1276 |
+
std::future<bool>& fut,
|
| 1277 |
+
const std::chrono::milliseconds& timeOutMilSec,
|
| 1278 |
+
const std::string& futDescription,
|
| 1279 |
+
::c10d::C10dLoggingData& debugLog,
|
| 1280 |
+
bool throwException = false);
|
| 1281 |
+
|
| 1282 |
+
// A helper function to guess the device id of the current rank, based on
|
| 1283 |
+
// bounded device or used device. Do not use this function if you already know
|
| 1284 |
+
// the device id to operate on.
|
| 1285 |
+
c10::DeviceIndex guessDeviceId() const;
|
| 1286 |
+
|
| 1287 |
+
static const int64_t kWatchdogThreadSleepMillis;
|
| 1288 |
+
|
| 1289 |
+
// The store is used to broadcast the NCCL unique ID of rank 0. This store
|
| 1290 |
+
// comes with prefix and it is different across ProcessGroup NCCL instances
|
| 1291 |
+
// (aka, different ProcessGroups).
|
| 1292 |
+
c10::intrusive_ptr<Store> store_;
|
| 1293 |
+
|
| 1294 |
+
// Reference to the store without prefix so that keys are same across all
|
| 1295 |
+
// ProcessGroup NCCL instances and (key, value) pairs written to the store are
|
| 1296 |
+
// global.
|
| 1297 |
+
c10::intrusive_ptr<Store> globalStore_;
|
| 1298 |
+
|
| 1299 |
+
// The lock which protects the write/read of
|
| 1300 |
+
// ephemeralTimeoutActive_/ephemeralTimeoutInflight_.
|
| 1301 |
+
// TODO(fduwjj): We need to have an audit on all mutexes we are adding here.
|
| 1302 |
+
// And consolidate them if possible.
|
| 1303 |
+
std::mutex mtxTimeoutExtension_;
|
| 1304 |
+
|
| 1305 |
+
// The ephemeral timeout added on top of existing timeout for works issued
|
| 1306 |
+
// before first work finishes.
|
| 1307 |
+
std::chrono::milliseconds ephemeralTimeoutActive_ =
|
| 1308 |
+
std::chrono::milliseconds(0);
|
| 1309 |
+
|
| 1310 |
+
// The ephemeral timeout addition which has been already applied to work.
|
| 1311 |
+
std::chrono::milliseconds ephemeralTimeoutInflight_ =
|
| 1312 |
+
std::chrono::milliseconds(0);
|
| 1313 |
+
|
| 1314 |
+
const c10::intrusive_ptr<Options> options_;
|
| 1315 |
+
|
| 1316 |
+
// The number of NCCL communicators that have been created during
|
| 1317 |
+
// the lifetime of this process group. This sequence number is
|
| 1318 |
+
// used to scope keys used in the store.
|
| 1319 |
+
uint64_t ncclCommCounter_{0};
|
| 1320 |
+
|
| 1321 |
+
// The NCCL communicator that the process group has cached.
|
| 1322 |
+
//
|
| 1323 |
+
// For collective operations:
|
| 1324 |
+
// The key is a list of GPU devices that an operation is operating on
|
| 1325 |
+
// The GPU devices are stored in a device sequence and the cache NCCL
|
| 1326 |
+
// communicator is associated with this GPU device sequence
|
| 1327 |
+
//
|
| 1328 |
+
// e.g. If the process group op only uses device 0, then the value of
|
| 1329 |
+
// the used device string stored (value of the hashmap) would be "0".
|
| 1330 |
+
//
|
| 1331 |
+
// If the process group op uses device 0 - 7 and the each tensor of the
|
| 1332 |
+
// input tensor list is on device, 0, 1, 2, 3, 4, 5, 6, 7 separately,
|
| 1333 |
+
// then the value of the used device string (key) stored would be
|
| 1334 |
+
// "0,1,2,3,4,5,6,7"
|
| 1335 |
+
//
|
| 1336 |
+
// If the process group op uses device 0 - 7 and the each tensor of the
|
| 1337 |
+
// input tensor list is on device, 0, 4, 5, 6, 7, 1, 2, 3 separately,
|
| 1338 |
+
// then the value of the used device string stored would be
|
| 1339 |
+
// "0,4,5,6,7,1,2,3"
|
| 1340 |
+
//
|
| 1341 |
+
// Note that the order of the device for the tensor list matters.
|
| 1342 |
+
//
|
| 1343 |
+
// For point-to-point operations:
|
| 1344 |
+
// The key is a string of my current rank and the peer process rank.
|
| 1345 |
+
// e.g. If process 1 and process 2 are involved in a point-to-point
|
| 1346 |
+
// communication, the key will be "1:2" on both processes. Note: this is for
|
| 1347 |
+
// the scenario where there is only 1 GPU per process. When it comes to
|
| 1348 |
+
// multiple GPUs per process, this part may need to redesigned.
|
| 1349 |
+
// TODO: we probably need a separate map for P2P comms
|
| 1350 |
+
std::unordered_map<std::string, std::shared_ptr<NCCLComm>> devNCCLCommMap_;
|
| 1351 |
+
|
| 1352 |
+
// The NCCL communicators currently in process of being initialized.
|
| 1353 |
+
std::unordered_map<std::string, std::shared_ptr<NCCLComm>>
|
| 1354 |
+
inInitializationCommMap_;
|
| 1355 |
+
|
| 1356 |
+
// Mutex to guard maps like devNCCLCommMap_.
|
| 1357 |
+
std::mutex mutex_;
|
| 1358 |
+
|
| 1359 |
+
// Size of ring buffer where we store NCCL Traces for debugging.
|
| 1360 |
+
int traceBufferSize_;
|
| 1361 |
+
|
| 1362 |
+
// Stores TORCH_NCCL_DEBUG_INFO_PIPE_FILE
|
| 1363 |
+
std::string debugInfoPipeFile_;
|
| 1364 |
+
|
| 1365 |
+
// We gate the cudaEventCache so that we can roll it out gradually.
|
| 1366 |
+
std::atomic<bool> cudaEventCacheEnabled_;
|
| 1367 |
+
|
| 1368 |
+
std::thread onCompletionHookThread_;
|
| 1369 |
+
|
| 1370 |
+
// Whether or not we should terminate the watchdog and workCleanup threads.
|
| 1371 |
+
std::atomic<bool> terminateProcessGroup_;
|
| 1372 |
+
|
| 1373 |
+
// Whether there are hooks pending to be fired
|
| 1374 |
+
std::atomic<bool> hasPendingHooks_;
|
| 1375 |
+
|
| 1376 |
+
// This is the signal from watchdog threads to indicate whether the monitor
|
| 1377 |
+
// thread should dump. Making it static so that it is accessible from all the
|
| 1378 |
+
// PGs. With this flag, monitor thread would dump debug info under any one of
|
| 1379 |
+
// the three conditions:
|
| 1380 |
+
//
|
| 1381 |
+
// 1: watchdog thread of any PG detects a collective timeout.
|
| 1382 |
+
// 2: timeout signal is received from other ranks through tcpstore.
|
| 1383 |
+
// 3: current PG's watchdog heartbeat timeout occurs.
|
| 1384 |
+
//
|
| 1385 |
+
// Note that only the monitor thread from PG0 will dump the debug info for
|
| 1386 |
+
// case one and two so that the debug info is only dumped once.
|
| 1387 |
+
static std::atomic<bool> shouldDump_;
|
| 1388 |
+
|
| 1389 |
+
// Mutex to Guard workMetaList_
|
| 1390 |
+
std::mutex workMetaListMutex_;
|
| 1391 |
+
|
| 1392 |
+
bool writeDebugInfo_ = false;
|
| 1393 |
+
|
| 1394 |
+
// Vector to store WorkNCCL pointers
|
| 1395 |
+
std::list<ProcessGroupNCCL::WorkNCCL> workMetaList_;
|
| 1396 |
+
|
| 1397 |
+
// Mutex to Guard workMetaList_
|
| 1398 |
+
std::mutex completedWorkListMutex_;
|
| 1399 |
+
|
| 1400 |
+
// Condition Variable for watchdog thread sleep
|
| 1401 |
+
std::condition_variable completedWorkListCV_;
|
| 1402 |
+
|
| 1403 |
+
std::list<ProcessGroupNCCL::WorkNCCL> completedWorkList_;
|
| 1404 |
+
|
| 1405 |
+
// Add Work Pointer to workVector
|
| 1406 |
+
void workEnqueue(
|
| 1407 |
+
const c10::intrusive_ptr<ProcessGroupNCCL::WorkNCCL>& /*work*/);
|
| 1408 |
+
|
| 1409 |
+
// The CUDA streams used by NCCL kernels
|
| 1410 |
+
std::unordered_map<std::string, at::cuda::CUDAStream> ncclStreams_;
|
| 1411 |
+
|
| 1412 |
+
// The CUDA events used to sync NCCL streams
|
| 1413 |
+
std::unordered_map<std::string, at::cuda::CUDAEvent> ncclEvents_;
|
| 1414 |
+
|
| 1415 |
+
// Device Indexes used for all collectives in this group
|
| 1416 |
+
std::set<c10::DeviceIndex> usedDeviceIdxs_;
|
| 1417 |
+
|
| 1418 |
+
// Flag to denote if a coalescing groupStart/groupEnd block is active
|
| 1419 |
+
int coalescing_state_ = 0;
|
| 1420 |
+
|
| 1421 |
+
// Stores device indexes for all collectives run inside a coalescing block
|
| 1422 |
+
at::Device coalescedDevice_ = at::Device("cuda");
|
| 1423 |
+
|
| 1424 |
+
// Stores communicators for all collectives run inside a coalescing block
|
| 1425 |
+
std::shared_ptr<NCCLComm> coalescedComm_ = nullptr;
|
| 1426 |
+
|
| 1427 |
+
// Whether the coalesced calls are sync or async.
|
| 1428 |
+
bool coalescedAsync_{};
|
| 1429 |
+
|
| 1430 |
+
// keeps track of input and output tensors when coalescing is in flight. Will
|
| 1431 |
+
// hand over these tensors to WorkNCCL's stash when coalescing is ended.
|
| 1432 |
+
TensorShelf coalescedTensors_;
|
| 1433 |
+
|
| 1434 |
+
// Some ops may have completed, but user still hasn't called `work.wait()`.
|
| 1435 |
+
// When watchdog detects this, it transfers the TensorShelf from `work` to
|
| 1436 |
+
// this `shelves` structure. Next time we execute ProcessGroupNCCL's methods
|
| 1437 |
+
// on main thread, we clear the `shelves` in one shot. This is mainly because
|
| 1438 |
+
// watchdog (a side thread) unstashing the shelf directly seems to cause some
|
| 1439 |
+
// problem.
|
| 1440 |
+
std::vector<std::shared_ptr<TensorShelf>> shelvesToUnstash_;
|
| 1441 |
+
std::mutex shelvesMutex_;
|
| 1442 |
+
|
| 1443 |
+
// Whether or not wait() and synchronize() are blocking operations that wait
|
| 1444 |
+
// for the operation to complete.
|
| 1445 |
+
bool blockingWait_ = false;
|
| 1446 |
+
|
| 1447 |
+
// Whether or not the workCleanupThread is used to perform async error
|
| 1448 |
+
// handling.
|
| 1449 |
+
ErrorHandlingMode asyncErrorHandling_ = NoHandling;
|
| 1450 |
+
|
| 1451 |
+
ErrorType error_ = ErrorType::SUCCESS;
|
| 1452 |
+
|
| 1453 |
+
std::mutex errorMutex_;
|
| 1454 |
+
|
| 1455 |
+
// Whether or not to sleep after an exception is thrown in the watchdog.
|
| 1456 |
+
bool sleepAfterException_{};
|
| 1457 |
+
|
| 1458 |
+
// Whether or not to enable nan check for input tensors to collectives.
|
| 1459 |
+
bool enableNanCheck_;
|
| 1460 |
+
|
| 1461 |
+
// Whether or not to create start CUDAEvent and enable timing for start
|
| 1462 |
+
// and end events. Note that enableTiming_ is always true if desyncDebug_
|
| 1463 |
+
// is set to true.
|
| 1464 |
+
std::atomic<bool> enableTiming_;
|
| 1465 |
+
|
| 1466 |
+
// Flag to enable the print of hash value of input/output of collectives for
|
| 1467 |
+
// verification.
|
| 1468 |
+
std::atomic<bool> enableCollectiveHashDebug_;
|
| 1469 |
+
|
| 1470 |
+
// Whether or not TORCH_NCCL_AVOID_RECORD_STREAMS was set
|
| 1471 |
+
bool avoidRecordStreams_ = false;
|
| 1472 |
+
|
| 1473 |
+
// The number of active ncclGroupStart() calls. This counter will be increased
|
| 1474 |
+
// by 1 when ncclGroupStart() is called and decreased by 1 when ncclGroupEnd()
|
| 1475 |
+
// is called.
|
| 1476 |
+
static thread_local uint64_t ncclActiveGroupCounter_;
|
| 1477 |
+
|
| 1478 |
+
// Counting for the sequential number of NCCL collective call.
|
| 1479 |
+
// (specifically, how many actual kernels we launched, which differs from
|
| 1480 |
+
// op_id_ when coalescing is enabled)
|
| 1481 |
+
uint64_t seqCollective_{0};
|
| 1482 |
+
|
| 1483 |
+
// Counting for the sequential number of NCCL P2P calls.
|
| 1484 |
+
uint64_t seqP2P_{0};
|
| 1485 |
+
|
| 1486 |
+
// Incrementing counter for logical operations (collective or p2p) issued on
|
| 1487 |
+
// the ProcessGroup
|
| 1488 |
+
uint64_t op_id_{0};
|
| 1489 |
+
|
| 1490 |
+
// The number of ProcessGroupNCCL created on the current rank.
|
| 1491 |
+
size_t local_id_;
|
| 1492 |
+
|
| 1493 |
+
std::string logPrefix_;
|
| 1494 |
+
|
| 1495 |
+
c10::intrusive_ptr<intra_node_comm::IntraNodeComm> intraNodeComm_;
|
| 1496 |
+
|
| 1497 |
+
// Number of devices on this node.
|
| 1498 |
+
int localDeviceCount_{0};
|
| 1499 |
+
|
| 1500 |
+
std::shared_ptr<ProcessGroupStatus> pgStatus_ =
|
| 1501 |
+
std::make_shared<ProcessGroupStatus>();
|
| 1502 |
+
|
| 1503 |
+
// Internal cached value: use NCCL non-blocking API mode or not.
|
| 1504 |
+
// Use `useNonblocking()` method instead of accessing this variable directly.
|
| 1505 |
+
std::optional<bool> useNonblocking_{std::nullopt};
|
| 1506 |
+
|
| 1507 |
+
// Communication-optimized memory pool associated with this PG
|
| 1508 |
+
std::unique_ptr<at::cuda::MemPool> memPool_ = nullptr;
|
| 1509 |
+
};
|
| 1510 |
+
|
| 1511 |
+
// Reset the flighrecorder recordings for the current rank.
|
| 1512 |
+
TORCH_API void reset_nccl_trace();
|
| 1513 |
+
|
| 1514 |
+
// Dumps the NCCL comm traces and additional information about the Process
|
| 1515 |
+
// Group.
|
| 1516 |
+
TORCH_API std::string dump_nccl_trace(
|
| 1517 |
+
bool includeCollectives,
|
| 1518 |
+
bool includeStackTraces,
|
| 1519 |
+
bool onlyActive);
|
| 1520 |
+
|
| 1521 |
+
// Dumps the NCCL comm traces and additional information about the Process
|
| 1522 |
+
// Group in JSON formatted string.
|
| 1523 |
+
// We don't include stack traces in JSON format as it is far too much data.
|
| 1524 |
+
TORCH_API std::string dump_nccl_trace_json(
|
| 1525 |
+
bool includeCollectives,
|
| 1526 |
+
bool onlyActive);
|
| 1527 |
+
|
| 1528 |
+
// Gets a mutable reference to a global optional function.Heartbeat Monitor
|
| 1529 |
+
// will use this function to dump traces, if available. Inside fbcode, we
|
| 1530 |
+
// store a function here that uses an internal tool for process tracing
|
| 1531 |
+
TORCH_API std::optional<
|
| 1532 |
+
std::function<void(std::function<void(const std::string&)>)>>&
|
| 1533 |
+
get_cpp_trace_dumper();
|
| 1534 |
+
|
| 1535 |
+
// Similar to get_cpp_trace_dumper, this stores a function defined in
|
| 1536 |
+
// torch-python layer that lets us check whether the GIL can be acquired,
|
| 1537 |
+
// helpful for instrumenting in cases where a hang was observed.
|
| 1538 |
+
typedef bool (*gil_checker_t)();
|
| 1539 |
+
|
| 1540 |
+
TORCH_API gil_checker_t& get_gil_checker();
|
| 1541 |
+
} // namespace c10d
|
| 1542 |
+
|
| 1543 |
+
#endif // USE_C10D_NCCL
|
| 1544 |
+
|
| 1545 |
+
#else
|
| 1546 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 1547 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupUCC.hpp
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#ifdef USE_C10D_UCC
|
| 5 |
+
|
| 6 |
+
#include <torch/csrc/distributed/c10d/UCCUtils.hpp>
|
| 7 |
+
|
| 8 |
+
#include <exception>
|
| 9 |
+
#include <memory>
|
| 10 |
+
#include <mutex>
|
| 11 |
+
#include <queue>
|
| 12 |
+
#include <thread>
|
| 13 |
+
#include <vector>
|
| 14 |
+
|
| 15 |
+
#include <torch/csrc/distributed/c10d/Backend.hpp>
|
| 16 |
+
#include <torch/csrc/distributed/c10d/Store.hpp>
|
| 17 |
+
#include <torch/csrc/distributed/c10d/Types.hpp>
|
| 18 |
+
#include <torch/csrc/distributed/c10d/Utils.hpp>
|
| 19 |
+
#ifdef USE_CUDA
|
| 20 |
+
#include <ATen/cuda/CUDAEvent.h>
|
| 21 |
+
#include <c10/cuda/CUDAStream.h>
|
| 22 |
+
#endif
|
| 23 |
+
|
| 24 |
+
namespace c10d {
|
| 25 |
+
|
| 26 |
+
#define TORCH_UCC_DEVICE_NOT_SET -2
|
| 27 |
+
|
| 28 |
+
#ifdef USE_CUDA
|
| 29 |
+
#define SAVE_TENSORS(_TENSORS, _DATA) \
|
| 30 |
+
do { \
|
| 31 |
+
if ((_TENSORS)[0].device().is_cuda()) { \
|
| 32 |
+
for (const auto i : c10::irange((_TENSORS).size())) { \
|
| 33 |
+
c10::cuda::CUDACachingAllocator::recordStream( \
|
| 34 |
+
(_TENSORS)[i].storage().data_ptr(), (*stream)); \
|
| 35 |
+
} \
|
| 36 |
+
} else { \
|
| 37 |
+
(_DATA) = (_TENSORS); \
|
| 38 |
+
} \
|
| 39 |
+
} while (0)
|
| 40 |
+
|
| 41 |
+
#else
|
| 42 |
+
#define SAVE_TENSORS(_TENSORS, _DATA) (_DATA) = (_TENSORS);
|
| 43 |
+
#endif
|
| 44 |
+
|
| 45 |
+
constexpr const char* UCC_BACKEND_NAME = "ucc";
|
| 46 |
+
|
| 47 |
+
struct event_pool_t {
|
| 48 |
+
#ifdef USE_CUDA
|
| 49 |
+
std::queue<std::unique_ptr<at::cuda::CUDAEvent>> event_pool;
|
| 50 |
+
#endif
|
| 51 |
+
std::mutex event_pool_mutex;
|
| 52 |
+
};
|
| 53 |
+
|
| 54 |
+
class Comm;
|
| 55 |
+
|
| 56 |
+
// UCC does not support multiple CUDA devices per process.
|
| 57 |
+
class TORCH_API ProcessGroupUCC : public Backend {
|
| 58 |
+
private:
|
| 59 |
+
void set_timeout(ucc_coll_args_t& args);
|
| 60 |
+
|
| 61 |
+
public:
|
| 62 |
+
class WorkData {
|
| 63 |
+
public:
|
| 64 |
+
std::vector<at::Tensor> src;
|
| 65 |
+
std::vector<at::Tensor> dst;
|
| 66 |
+
std::vector<at::Tensor> flat;
|
| 67 |
+
WorkData() {}
|
| 68 |
+
virtual ~WorkData() = default;
|
| 69 |
+
};
|
| 70 |
+
class AlltoallWorkData : public WorkData {
|
| 71 |
+
public:
|
| 72 |
+
AlltoallWorkData(int size)
|
| 73 |
+
: send_lengths(size),
|
| 74 |
+
send_offsets(size),
|
| 75 |
+
recv_lengths(size),
|
| 76 |
+
recv_offsets(size) {}
|
| 77 |
+
std::vector<uint64_t> send_lengths;
|
| 78 |
+
std::vector<uint64_t> send_offsets;
|
| 79 |
+
std::vector<uint64_t> recv_lengths;
|
| 80 |
+
std::vector<uint64_t> recv_offsets;
|
| 81 |
+
};
|
| 82 |
+
|
| 83 |
+
class AllgathervWorkData : public WorkData {
|
| 84 |
+
public:
|
| 85 |
+
AllgathervWorkData(int size) : recv_lengths(size), recv_offsets(size) {}
|
| 86 |
+
std::vector<uint64_t> recv_lengths;
|
| 87 |
+
std::vector<uint64_t> recv_offsets;
|
| 88 |
+
};
|
| 89 |
+
|
| 90 |
+
class ScattervWorkData : public WorkData {
|
| 91 |
+
public:
|
| 92 |
+
ScattervWorkData(int size) : send_lengths(size), send_offsets(size) {}
|
| 93 |
+
std::vector<uint64_t> send_lengths;
|
| 94 |
+
std::vector<uint64_t> send_offsets;
|
| 95 |
+
};
|
| 96 |
+
|
| 97 |
+
class ProgressEntry {
|
| 98 |
+
friend class ProcessGroupUCC;
|
| 99 |
+
friend class Comm;
|
| 100 |
+
|
| 101 |
+
public:
|
| 102 |
+
ProgressEntry(CommBase* comm, ucc_coll_req_h request)
|
| 103 |
+
: status_(UCC_INPROGRESS), comm_(comm), request_(request) {}
|
| 104 |
+
// Finalizes UCC status or exception of collective request.
|
| 105 |
+
void finalize(std::exception_ptr eptr = nullptr);
|
| 106 |
+
ucc_status_t status_;
|
| 107 |
+
CommBase* comm_;
|
| 108 |
+
ucc_coll_req_h request_;
|
| 109 |
+
std::unique_ptr<WorkData> data;
|
| 110 |
+
c10::intrusive_ptr<c10::ivalue::Future> future_;
|
| 111 |
+
std::exception_ptr eptr_;
|
| 112 |
+
};
|
| 113 |
+
|
| 114 |
+
class WorkUCC : public Work {
|
| 115 |
+
friend class ProcessGroupUCC;
|
| 116 |
+
friend class Comm;
|
| 117 |
+
|
| 118 |
+
public:
|
| 119 |
+
WorkUCC(
|
| 120 |
+
OpType opType,
|
| 121 |
+
uint64_t seq,
|
| 122 |
+
const char* prof_title,
|
| 123 |
+
const std::optional<std::vector<at::Tensor>>& inputs,
|
| 124 |
+
const c10::intrusive_ptr<ProcessGroupUCCLogger>& logger)
|
| 125 |
+
: Work(-1, opType, prof_title, inputs), logger_(logger), seq_(seq) {}
|
| 126 |
+
~WorkUCC();
|
| 127 |
+
void setException();
|
| 128 |
+
void setAndThrowException();
|
| 129 |
+
bool isCompleted() override;
|
| 130 |
+
bool isSuccess() const override;
|
| 131 |
+
bool wait(std::chrono::milliseconds timeout = kUnsetTimeout) override;
|
| 132 |
+
c10::intrusive_ptr<c10::ivalue::Future> getFuture() override;
|
| 133 |
+
std::vector<at::Tensor> result() override;
|
| 134 |
+
int sourceRank() const override;
|
| 135 |
+
#ifdef USE_CUDA
|
| 136 |
+
std::unique_ptr<at::cuda::CUDAEvent> fence = nullptr;
|
| 137 |
+
event_pool_t* ep = nullptr;
|
| 138 |
+
#endif
|
| 139 |
+
int sourceRank_;
|
| 140 |
+
|
| 141 |
+
protected:
|
| 142 |
+
std::shared_ptr<ProgressEntry> entry_;
|
| 143 |
+
c10::intrusive_ptr<ProcessGroupUCCLogger> logger_;
|
| 144 |
+
uint64_t seq_;
|
| 145 |
+
|
| 146 |
+
private:
|
| 147 |
+
// The future returned by getFuture.
|
| 148 |
+
c10::intrusive_ptr<at::ivalue::Future> future_;
|
| 149 |
+
// Store a reference to collective's outputs, used by result
|
| 150 |
+
std::shared_ptr<std::vector<at::Tensor>> outputs_;
|
| 151 |
+
};
|
| 152 |
+
|
| 153 |
+
explicit ProcessGroupUCC(
|
| 154 |
+
const c10::intrusive_ptr<Store>& store,
|
| 155 |
+
int rank = -1,
|
| 156 |
+
int size = -1,
|
| 157 |
+
std::chrono::duration<float> timeout = kBackendDefaultTimeout);
|
| 158 |
+
|
| 159 |
+
void initComm(c10::Device dev);
|
| 160 |
+
|
| 161 |
+
~ProcessGroupUCC() override;
|
| 162 |
+
|
| 163 |
+
const std::string getBackendName() const override {
|
| 164 |
+
return std::string(UCC_BACKEND_NAME);
|
| 165 |
+
}
|
| 166 |
+
|
| 167 |
+
#ifdef USE_CUDA
|
| 168 |
+
std::unique_ptr<at::cuda::CUDAEvent> getPooledEvent();
|
| 169 |
+
#endif
|
| 170 |
+
|
| 171 |
+
// Performs a health check by initializing dummy UCC & UCX communicators and
|
| 172 |
+
// then destroying them. This will help indicate and signal any
|
| 173 |
+
// UCC/UCX-related issues prior to the first collective. The actual
|
| 174 |
+
// initialization and subsequent destruction is ran on a separate thread and
|
| 175 |
+
// the main thread is signalled about timeouts/errors to report to the
|
| 176 |
+
// application.
|
| 177 |
+
void runHealthCheck();
|
| 178 |
+
|
| 179 |
+
template <typename PreProcess, typename PostProcess>
|
| 180 |
+
c10::intrusive_ptr<Work> collective_post(
|
| 181 |
+
OpType opType,
|
| 182 |
+
PreProcess preproc,
|
| 183 |
+
PostProcess postproc,
|
| 184 |
+
ucc_coll_args_t& coll,
|
| 185 |
+
std::unique_ptr<ProcessGroupUCC::WorkData> data,
|
| 186 |
+
c10::Device dev,
|
| 187 |
+
std::vector<at::Tensor>& inputTensors,
|
| 188 |
+
std::vector<at::Tensor>& outputTensors,
|
| 189 |
+
const char* prof_title);
|
| 190 |
+
|
| 191 |
+
c10::intrusive_ptr<Work> broadcast(
|
| 192 |
+
std::vector<at::Tensor>& data,
|
| 193 |
+
const BroadcastOptions& opts = BroadcastOptions()) override;
|
| 194 |
+
|
| 195 |
+
c10::intrusive_ptr<Work> allreduce(
|
| 196 |
+
std::vector<at::Tensor>& tensors,
|
| 197 |
+
const AllreduceOptions& opts = AllreduceOptions()) override;
|
| 198 |
+
|
| 199 |
+
c10::intrusive_ptr<Work> allreduce_coalesced(
|
| 200 |
+
std::vector<at::Tensor>& tensors,
|
| 201 |
+
const AllreduceCoalescedOptions& opts =
|
| 202 |
+
AllreduceCoalescedOptions()) override;
|
| 203 |
+
|
| 204 |
+
c10::intrusive_ptr<Work> reduce(
|
| 205 |
+
std::vector<at::Tensor>& tensors,
|
| 206 |
+
const ReduceOptions& opts = ReduceOptions()) override;
|
| 207 |
+
|
| 208 |
+
c10::intrusive_ptr<Work> allgather(
|
| 209 |
+
std::vector<std::vector<at::Tensor>>& outputTensors,
|
| 210 |
+
std::vector<at::Tensor>& inputTensors,
|
| 211 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 212 |
+
|
| 213 |
+
c10::intrusive_ptr<Work> _allgather_base(
|
| 214 |
+
at::Tensor& outputBuffer,
|
| 215 |
+
at::Tensor& inputBuffer,
|
| 216 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 217 |
+
|
| 218 |
+
c10::intrusive_ptr<Work> barrier(
|
| 219 |
+
const BarrierOptions& opts = BarrierOptions()) override;
|
| 220 |
+
|
| 221 |
+
c10::intrusive_ptr<Work> gather(
|
| 222 |
+
std::vector<std::vector<at::Tensor>>& outputTensors,
|
| 223 |
+
std::vector<at::Tensor>& inputTensors,
|
| 224 |
+
const GatherOptions& opts = GatherOptions()) override;
|
| 225 |
+
|
| 226 |
+
c10::intrusive_ptr<Work> scatter(
|
| 227 |
+
std::vector<at::Tensor>& outputTensors,
|
| 228 |
+
std::vector<std::vector<at::Tensor>>& inputTensors,
|
| 229 |
+
const ScatterOptions& opts = ScatterOptions()) override;
|
| 230 |
+
|
| 231 |
+
c10::intrusive_ptr<Work> reduce_scatter(
|
| 232 |
+
std::vector<at::Tensor>& outputTensors,
|
| 233 |
+
std::vector<std::vector<at::Tensor>>& inputTensors,
|
| 234 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override;
|
| 235 |
+
|
| 236 |
+
c10::intrusive_ptr<Work> _reduce_scatter_base(
|
| 237 |
+
at::Tensor& outputTensor,
|
| 238 |
+
at::Tensor& inputTensor,
|
| 239 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override;
|
| 240 |
+
|
| 241 |
+
c10::intrusive_ptr<Work> alltoall_base(
|
| 242 |
+
at::Tensor& outputTensor,
|
| 243 |
+
at::Tensor& inputTensor,
|
| 244 |
+
std::vector<int64_t>& outputSplitSizes,
|
| 245 |
+
std::vector<int64_t>& inputSplitSizes,
|
| 246 |
+
const AllToAllOptions& opts = AllToAllOptions()) override;
|
| 247 |
+
|
| 248 |
+
c10::intrusive_ptr<Work> alltoall(
|
| 249 |
+
std::vector<at::Tensor>& outputTensors,
|
| 250 |
+
std::vector<at::Tensor>& inputTensors,
|
| 251 |
+
const AllToAllOptions& opts = AllToAllOptions()) override;
|
| 252 |
+
|
| 253 |
+
c10::intrusive_ptr<Work> send(
|
| 254 |
+
std::vector<at::Tensor>& tensors,
|
| 255 |
+
int dstRank,
|
| 256 |
+
int tag) override;
|
| 257 |
+
|
| 258 |
+
c10::intrusive_ptr<Work> recv(
|
| 259 |
+
std::vector<at::Tensor>& tensors,
|
| 260 |
+
int srcRank,
|
| 261 |
+
int tag) override;
|
| 262 |
+
|
| 263 |
+
// Counting for the sequential number of UCC collective_post call.
|
| 264 |
+
uint64_t seq_{0};
|
| 265 |
+
|
| 266 |
+
// Agrees on an initial sequence number for the whole group by having rank 0
|
| 267 |
+
// create it and broadcast it to other ranks using the store.
|
| 268 |
+
void setSequenceNumberForGroup() override;
|
| 269 |
+
|
| 270 |
+
// Retrieves the current sequence number for the whole group, which should be
|
| 271 |
+
// in sync. If the returned number is not consistent across the group, it
|
| 272 |
+
// may indicate that there is some sort of collective desynchronization.
|
| 273 |
+
uint64_t getSequenceNumberForGroup() override;
|
| 274 |
+
|
| 275 |
+
static c10::intrusive_ptr<Backend> createProcessGroupUCC(
|
| 276 |
+
const c10::intrusive_ptr<::c10d::Store>& store,
|
| 277 |
+
int rank,
|
| 278 |
+
int size,
|
| 279 |
+
const std::chrono::duration<float>& timeout);
|
| 280 |
+
|
| 281 |
+
protected:
|
| 282 |
+
const std::chrono::duration<float> timeout_;
|
| 283 |
+
std::shared_ptr<torch_ucc_oob_coll_info_t> oob;
|
| 284 |
+
std::shared_ptr<Comm> comm = {nullptr};
|
| 285 |
+
uint32_t comm_id;
|
| 286 |
+
ucc_team_h team{nullptr};
|
| 287 |
+
ucc_ee_h cuda_ee{nullptr};
|
| 288 |
+
ucc_ee_h cuda_ee_p2p[2]{nullptr, nullptr};
|
| 289 |
+
|
| 290 |
+
#ifdef USE_CUDA
|
| 291 |
+
std::unique_ptr<at::cuda::CUDAStream> stream = nullptr;
|
| 292 |
+
std::unique_ptr<at::cuda::CUDAStream> stream_p2p[2] = {nullptr, nullptr};
|
| 293 |
+
event_pool_t ep;
|
| 294 |
+
#endif
|
| 295 |
+
c10::intrusive_ptr<ProcessGroupUCCLogger> logger;
|
| 296 |
+
};
|
| 297 |
+
|
| 298 |
+
class Comm {
|
| 299 |
+
c10::intrusive_ptr<ProcessGroupUCCLogger> logger;
|
| 300 |
+
std::shared_ptr<torch_ucc_oob_coll_info_t> oob;
|
| 301 |
+
CommUCC ucc_comm;
|
| 302 |
+
std::mutex mutex;
|
| 303 |
+
std::thread progress_thread;
|
| 304 |
+
std::condition_variable queue_produce_cv;
|
| 305 |
+
std::condition_variable queue_consume_cv;
|
| 306 |
+
std::deque<std::shared_ptr<ProcessGroupUCC::ProgressEntry>> progress_queue;
|
| 307 |
+
bool stop_progress_loop;
|
| 308 |
+
bool collective_inprogress;
|
| 309 |
+
torch_ucc_phase_t finalize_phase;
|
| 310 |
+
|
| 311 |
+
public:
|
| 312 |
+
c10::DeviceIndex cuda_device_index;
|
| 313 |
+
Comm(
|
| 314 |
+
const c10::intrusive_ptr<ProcessGroupUCCLogger>& logger,
|
| 315 |
+
std::shared_ptr<torch_ucc_oob_coll_info_t> oob,
|
| 316 |
+
c10::Device dev,
|
| 317 |
+
bool is_health_check);
|
| 318 |
+
|
| 319 |
+
~Comm();
|
| 320 |
+
|
| 321 |
+
void ucc_create_team(
|
| 322 |
+
ucc_team_h& team,
|
| 323 |
+
std::shared_ptr<torch_ucc_oob_coll_info_t> oob);
|
| 324 |
+
|
| 325 |
+
void ucc_destroy_team(ucc_team_h& team);
|
| 326 |
+
|
| 327 |
+
c10::intrusive_ptr<Work> enqueue_p2p(
|
| 328 |
+
OpType opType,
|
| 329 |
+
ucc_coll_req_h request,
|
| 330 |
+
const char* prof_title);
|
| 331 |
+
|
| 332 |
+
#ifdef USE_CUDA
|
| 333 |
+
void enqueue_cuda_collective(
|
| 334 |
+
std::unique_ptr<ProcessGroupUCC::WorkData> data,
|
| 335 |
+
c10::intrusive_ptr<ProcessGroupUCC::WorkUCC> work,
|
| 336 |
+
ucc_coll_args_t& coll,
|
| 337 |
+
ucc_team_h team,
|
| 338 |
+
ucc_ee_h ee);
|
| 339 |
+
#endif
|
| 340 |
+
|
| 341 |
+
void enqueue_collective(
|
| 342 |
+
std::unique_ptr<ProcessGroupUCC::WorkData> data,
|
| 343 |
+
c10::intrusive_ptr<ProcessGroupUCC::WorkUCC> work,
|
| 344 |
+
ucc_coll_args_t& coll,
|
| 345 |
+
ucc_team_h team);
|
| 346 |
+
|
| 347 |
+
static std::shared_ptr<Comm> get_comm(
|
| 348 |
+
uint32_t& id,
|
| 349 |
+
c10::Device dev,
|
| 350 |
+
std::shared_ptr<torch_ucc_oob_coll_info_t> oob,
|
| 351 |
+
const c10::intrusive_ptr<ProcessGroupUCCLogger>& logger,
|
| 352 |
+
bool is_health_check = false);
|
| 353 |
+
|
| 354 |
+
void progress_loop();
|
| 355 |
+
};
|
| 356 |
+
|
| 357 |
+
} // namespace c10d
|
| 358 |
+
|
| 359 |
+
#endif // USE_C10D_UCC
|
| 360 |
+
|
| 361 |
+
#else
|
| 362 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 363 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupWrapper.hpp
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#ifdef USE_C10D_GLOO
|
| 5 |
+
|
| 6 |
+
#include <torch/csrc/distributed/c10d/ProcessGroupGloo.hpp>
|
| 7 |
+
#include <torch/csrc/distributed/c10d/Types.hpp>
|
| 8 |
+
#include <torch/csrc/distributed/c10d/Utils.hpp>
|
| 9 |
+
|
| 10 |
+
namespace c10d {
|
| 11 |
+
|
| 12 |
+
// ProcessGroupWrapper wraps a Backend for debugging purposes. It intercepts
|
| 13 |
+
// collective operations to verify consistency across ranks before dispatching
|
| 14 |
+
// to the wrapped backend.
|
| 15 |
+
//
|
| 16 |
+
// IMPORTANT: This wrapper must forward all Backend virtual methods to backend_.
|
| 17 |
+
// When adding new virtual methods to Backend that are overridden by backends
|
| 18 |
+
// like ProcessGroupNCCL, you must also add forwarding methods here. Otherwise,
|
| 19 |
+
// those methods will fail when TORCH_DISTRIBUTED_DEBUG=DETAIL is set.
|
| 20 |
+
// See https://github.com/pytorch/pytorch/issues/173538 for an example.
|
| 21 |
+
class TORCH_API ProcessGroupWrapper : public Backend {
|
| 22 |
+
public:
|
| 23 |
+
explicit ProcessGroupWrapper(
|
| 24 |
+
const c10::intrusive_ptr<Backend>& backend,
|
| 25 |
+
c10::intrusive_ptr<Backend> glooBackend);
|
| 26 |
+
|
| 27 |
+
c10::intrusive_ptr<Work> broadcast(
|
| 28 |
+
std::vector<at::Tensor>& data,
|
| 29 |
+
const BroadcastOptions& opts = BroadcastOptions()) override;
|
| 30 |
+
|
| 31 |
+
c10::intrusive_ptr<Work> allreduce(
|
| 32 |
+
std::vector<at::Tensor>& data,
|
| 33 |
+
const AllreduceOptions& opts = AllreduceOptions()) override;
|
| 34 |
+
|
| 35 |
+
c10::intrusive_ptr<Work> allreduce_sparse(
|
| 36 |
+
std::vector<at::Tensor>& tensors,
|
| 37 |
+
const AllreduceOptions& opts = AllreduceOptions()) override;
|
| 38 |
+
|
| 39 |
+
c10::intrusive_ptr<Work> allreduce_coalesced(
|
| 40 |
+
std::vector<at::Tensor>& tensors,
|
| 41 |
+
const AllreduceCoalescedOptions& opts =
|
| 42 |
+
AllreduceCoalescedOptions()) override;
|
| 43 |
+
|
| 44 |
+
c10::intrusive_ptr<Work> reduce(
|
| 45 |
+
std::vector<at::Tensor>& tensors,
|
| 46 |
+
const ReduceOptions& opts = ReduceOptions()) override;
|
| 47 |
+
|
| 48 |
+
c10::intrusive_ptr<Work> allgather(
|
| 49 |
+
std::vector<std::vector<at::Tensor>>& outputTensors,
|
| 50 |
+
std::vector<at::Tensor>& inputTensors,
|
| 51 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 52 |
+
|
| 53 |
+
c10::intrusive_ptr<Work> _allgather_base(
|
| 54 |
+
at::Tensor& outputBuffer,
|
| 55 |
+
at::Tensor& inputBuffer,
|
| 56 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 57 |
+
|
| 58 |
+
// This function is deprecated and will be moved out of ProcessGroup to comms:
|
| 59 |
+
// * do not add dependencies on this function,
|
| 60 |
+
// * do not implement it in your ProcessGroup, implement _allgather_base
|
| 61 |
+
// instead.
|
| 62 |
+
c10::intrusive_ptr<Work> allgather_coalesced(
|
| 63 |
+
std::vector<std::vector<at::Tensor>>& outputTensorLists,
|
| 64 |
+
std::vector<at::Tensor>& inputTensors,
|
| 65 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 66 |
+
|
| 67 |
+
c10::intrusive_ptr<Work> allgather_into_tensor_coalesced(
|
| 68 |
+
std::vector<at::Tensor>& outputs,
|
| 69 |
+
std::vector<at::Tensor>& inputs,
|
| 70 |
+
const AllgatherOptions& opts = AllgatherOptions()) override;
|
| 71 |
+
|
| 72 |
+
c10::intrusive_ptr<Work> gather(
|
| 73 |
+
std::vector<std::vector<at::Tensor>>& outputTensors,
|
| 74 |
+
std::vector<at::Tensor>& inputTensors,
|
| 75 |
+
const GatherOptions& opts = GatherOptions()) override;
|
| 76 |
+
|
| 77 |
+
c10::intrusive_ptr<Work> scatter(
|
| 78 |
+
std::vector<at::Tensor>& outputTensors,
|
| 79 |
+
std::vector<std::vector<at::Tensor>>& inputTensors,
|
| 80 |
+
const ScatterOptions& opts = ScatterOptions()) override;
|
| 81 |
+
|
| 82 |
+
c10::intrusive_ptr<Work> reduce_scatter(
|
| 83 |
+
std::vector<at::Tensor>& outputTensors,
|
| 84 |
+
std::vector<std::vector<at::Tensor>>& inputTensors,
|
| 85 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override;
|
| 86 |
+
|
| 87 |
+
c10::intrusive_ptr<Work> _reduce_scatter_base(
|
| 88 |
+
at::Tensor& inputBuffer,
|
| 89 |
+
at::Tensor& outputBuffer,
|
| 90 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override;
|
| 91 |
+
|
| 92 |
+
c10::intrusive_ptr<Work> reduce_scatter_tensor_coalesced(
|
| 93 |
+
std::vector<at::Tensor>& outputs,
|
| 94 |
+
std::vector<at::Tensor>& inputs,
|
| 95 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override;
|
| 96 |
+
|
| 97 |
+
c10::intrusive_ptr<Work> alltoall_base(
|
| 98 |
+
at::Tensor& outputTensor,
|
| 99 |
+
at::Tensor& inputTensor,
|
| 100 |
+
std::vector<int64_t>& outputSplitSizes,
|
| 101 |
+
std::vector<int64_t>& inputSplitSizes,
|
| 102 |
+
const AllToAllOptions& opts = AllToAllOptions()) override;
|
| 103 |
+
|
| 104 |
+
c10::intrusive_ptr<Work> alltoall(
|
| 105 |
+
std::vector<at::Tensor>& outputTensors,
|
| 106 |
+
std::vector<at::Tensor>& inputTensors,
|
| 107 |
+
const AllToAllOptions& opts = AllToAllOptions()) override;
|
| 108 |
+
|
| 109 |
+
void monitoredBarrier(const BarrierOptions& opts, bool waitAllRanks = false)
|
| 110 |
+
override;
|
| 111 |
+
|
| 112 |
+
// Agrees on an initial sequence number for the whole group by having rank 0
|
| 113 |
+
// create it and broadcast it to other ranks using the store. Only implemented
|
| 114 |
+
// for GLOO and NCCL backends currently.
|
| 115 |
+
// dont implement this
|
| 116 |
+
void setSequenceNumberForGroup() override;
|
| 117 |
+
|
| 118 |
+
// Retrieves the current sequence number for the whole group, which should be
|
| 119 |
+
// in sync. If the returned number is not consistent across the group, it
|
| 120 |
+
// may indicate that there is some sort of collective desynchronization.
|
| 121 |
+
uint64_t getSequenceNumberForGroup() override; // just call underlying
|
| 122 |
+
|
| 123 |
+
c10::intrusive_ptr<Work> send(
|
| 124 |
+
std::vector<at::Tensor>& tensors,
|
| 125 |
+
int dstRank,
|
| 126 |
+
int tag) override;
|
| 127 |
+
|
| 128 |
+
c10::intrusive_ptr<Work> recv(
|
| 129 |
+
std::vector<at::Tensor>& tensors,
|
| 130 |
+
int srcRank,
|
| 131 |
+
int tag) override;
|
| 132 |
+
|
| 133 |
+
c10::intrusive_ptr<Work> recvAnysource(
|
| 134 |
+
std::vector<at::Tensor>& tensors,
|
| 135 |
+
int tag) override;
|
| 136 |
+
|
| 137 |
+
c10::intrusive_ptr<Work> barrier(
|
| 138 |
+
const BarrierOptions& opts = BarrierOptions()) override;
|
| 139 |
+
void registerOnCompletionHook(
|
| 140 |
+
std::function<void(std::shared_ptr<WorkInfo>)>&& hook) override;
|
| 141 |
+
|
| 142 |
+
void waitForPendingWorks() override;
|
| 143 |
+
void enableCollectivesTiming() override;
|
| 144 |
+
|
| 145 |
+
c10::intrusive_ptr<Backend> split(
|
| 146 |
+
const c10::intrusive_ptr<Store>& store,
|
| 147 |
+
const std::vector<int>& ranks,
|
| 148 |
+
const c10::intrusive_ptr<Options>& opts) override;
|
| 149 |
+
|
| 150 |
+
c10::intrusive_ptr<Backend> merge(
|
| 151 |
+
const c10::intrusive_ptr<Store>& store,
|
| 152 |
+
const c10::intrusive_ptr<Options>& opts,
|
| 153 |
+
const int& rank,
|
| 154 |
+
const int& size) override;
|
| 155 |
+
|
| 156 |
+
// Forward methods to wrapped backend
|
| 157 |
+
bool supportsSplitting() const override;
|
| 158 |
+
bool supportsCoalescing() const override;
|
| 159 |
+
bool supportsTimeEstimation() const override;
|
| 160 |
+
bool supportsShrinking() const override;
|
| 161 |
+
c10::intrusive_ptr<Backend> shrink(
|
| 162 |
+
const std::vector<int64_t>& ranks_to_exclude,
|
| 163 |
+
int shrink_flags = 0,
|
| 164 |
+
const c10::intrusive_ptr<Options>& opts_override = nullptr) override;
|
| 165 |
+
void setTimeout(std::chrono::milliseconds timeout) override;
|
| 166 |
+
void startCoalescing() override;
|
| 167 |
+
c10::intrusive_ptr<Work> endCoalescing() override;
|
| 168 |
+
const std::string getBackendName() const override;
|
| 169 |
+
c10::intrusive_ptr<Options> getBackendOptions() override;
|
| 170 |
+
std::shared_ptr<c10::Allocator> getMemAllocator() override;
|
| 171 |
+
at::Tensor allocateTensor(long size, at::TensorOptions options = {}) override;
|
| 172 |
+
bool supportsTensorAlloc(c10::DeviceIndex deviceIdx) override;
|
| 173 |
+
void abort() override;
|
| 174 |
+
void shutdown() override;
|
| 175 |
+
void suspend() override;
|
| 176 |
+
void resume() override;
|
| 177 |
+
std::unordered_map<std::string, uint64_t> getMemoryStats() override;
|
| 178 |
+
|
| 179 |
+
ErrorType getError() override;
|
| 180 |
+
void eagerConnectSingleDevice(at::Device device) override;
|
| 181 |
+
|
| 182 |
+
c10::intrusive_ptr<Backend> getWrappedPg() const;
|
| 183 |
+
|
| 184 |
+
private:
|
| 185 |
+
// Underlying process group that actual application collectives will be
|
| 186 |
+
// dispatched to
|
| 187 |
+
c10::intrusive_ptr<Backend> backend_;
|
| 188 |
+
// Gloo process group responsible for internal coordination such as monitored
|
| 189 |
+
// barrier, sequence number checking, collective fingerprint collecting.
|
| 190 |
+
c10::intrusive_ptr<Backend> glooBackend_;
|
| 191 |
+
// Conducts several checks to ensure that the underlying collective is well
|
| 192 |
+
// formed with the goal of notifying the user about incorrect collective use
|
| 193 |
+
// in the application.
|
| 194 |
+
void runCollectiveChecks(
|
| 195 |
+
OpType op_type,
|
| 196 |
+
const std::vector<at::Tensor>& tensors);
|
| 197 |
+
};
|
| 198 |
+
} // namespace c10d
|
| 199 |
+
|
| 200 |
+
#endif // USE_C10D_GLOO
|
| 201 |
+
|
| 202 |
+
#else
|
| 203 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 204 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/PyProcessGroup.hpp
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <torch/csrc/distributed/c10d/ProcessGroup.hpp>
|
| 5 |
+
#include <torch/csrc/jit/python/pybind_utils.h>
|
| 6 |
+
#include <torch/csrc/utils/pybind.h>
|
| 7 |
+
|
| 8 |
+
namespace c10d {
|
| 9 |
+
|
| 10 |
+
// PyProcessGroup is a pybind11 trampoline class to allow a Python
|
| 11 |
+
// class to inherit from torch.distributed.ProcessGroup
|
| 12 |
+
class PyProcessGroup : public ProcessGroup {
|
| 13 |
+
public:
|
| 14 |
+
// PyWork is a pybind11 trampoline class to allow a Python
|
| 15 |
+
// class to inherit from torch.distributed.Work
|
| 16 |
+
class TORCH_PYTHON_API PyWork : public Work {
|
| 17 |
+
public:
|
| 18 |
+
PyWork() = default;
|
| 19 |
+
|
| 20 |
+
bool wait(std::chrono::milliseconds timeout = kNoTimeout) override {
|
| 21 |
+
PYBIND11_OVERRIDE(
|
| 22 |
+
bool, /* Return type */
|
| 23 |
+
Work, /* Parent class */
|
| 24 |
+
wait, /* Name of function in C++ */
|
| 25 |
+
timeout);
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
c10::intrusive_ptr<c10::ivalue::Future> getFuture() override {
|
| 29 |
+
// We cannot use PYBIND11_OVERRIDE because:
|
| 30 |
+
// 1. We have to >MANUALLY< unwrap the PyFutureWrapper and
|
| 31 |
+
// 2. The python name is get_future
|
| 32 |
+
pybind11::gil_scoped_acquire gil;
|
| 33 |
+
auto override =
|
| 34 |
+
pybind11::get_override(static_cast<const Work*>(this), "get_future");
|
| 35 |
+
|
| 36 |
+
if (override) {
|
| 37 |
+
py::object o = override();
|
| 38 |
+
auto futWrapper =
|
| 39 |
+
o.cast<std::shared_ptr<torch::jit::PythonFutureWrapper>>();
|
| 40 |
+
return futWrapper->fut;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
return Work::getFuture();
|
| 44 |
+
}
|
| 45 |
+
};
|
| 46 |
+
|
| 47 |
+
#define WORK_OVERRIDE(cname, name, ...) \
|
| 48 |
+
do { \
|
| 49 |
+
pybind11::gil_scoped_acquire gil; \
|
| 50 |
+
pybind11::function override = \
|
| 51 |
+
pybind11::get_override(static_cast<const cname*>(this), #name); \
|
| 52 |
+
if (override) { \
|
| 53 |
+
auto o = override(__VA_ARGS__); \
|
| 54 |
+
return c10::make_intrusive<PyWorkHolder>(o); \
|
| 55 |
+
} \
|
| 56 |
+
return cname::name(__VA_ARGS__); \
|
| 57 |
+
} while (false)
|
| 58 |
+
|
| 59 |
+
// This class is used to wrap a PyWork trampoline with it's corresponding
|
| 60 |
+
// Python object to prevent the Python object from being garbage collected.
|
| 61 |
+
class PyWorkHolder : public Work {
|
| 62 |
+
public:
|
| 63 |
+
PyWorkHolder(const c10::intrusive_ptr<Work>& work, py::object pyWork)
|
| 64 |
+
: work_(work), pyWork_(std::move(pyWork)) {}
|
| 65 |
+
|
| 66 |
+
PyWorkHolder(py::object pyWork)
|
| 67 |
+
: work_(pyWork.cast<c10::intrusive_ptr<Work>>()),
|
| 68 |
+
pyWork_(std::move(pyWork)) {}
|
| 69 |
+
|
| 70 |
+
~PyWorkHolder() override {
|
| 71 |
+
// GIL must be held when freeing python objects.
|
| 72 |
+
py::gil_scoped_acquire gil;
|
| 73 |
+
pyWork_ = py::object();
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
bool wait(std::chrono::milliseconds timeout = kNoTimeout) override {
|
| 77 |
+
return work_->wait(timeout);
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
c10::intrusive_ptr<c10::ivalue::Future> getFuture() override {
|
| 81 |
+
return work_->getFuture();
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
private:
|
| 85 |
+
c10::intrusive_ptr<Work> work_;
|
| 86 |
+
py::object pyWork_;
|
| 87 |
+
};
|
| 88 |
+
|
| 89 |
+
using ProcessGroup::ProcessGroup;
|
| 90 |
+
|
| 91 |
+
const std::string getBackendName() const override {
|
| 92 |
+
PYBIND11_OVERRIDE(
|
| 93 |
+
std::string, /* Return type */
|
| 94 |
+
ProcessGroup, /* Parent class */
|
| 95 |
+
getBackendName, /* Name of function in C++ */
|
| 96 |
+
);
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
int getRank() const override {
|
| 100 |
+
PYBIND11_OVERRIDE(
|
| 101 |
+
int, /* Return type */
|
| 102 |
+
ProcessGroup, /* Parent class */
|
| 103 |
+
getRank, /* Name of function in C++ */
|
| 104 |
+
);
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
int getSize() const override {
|
| 108 |
+
PYBIND11_OVERRIDE(
|
| 109 |
+
int, /* Return type */
|
| 110 |
+
ProcessGroup, /* Parent class */
|
| 111 |
+
getSize, /* Name of function in C++ */
|
| 112 |
+
);
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
void abort() override {
|
| 116 |
+
PYBIND11_OVERRIDE(
|
| 117 |
+
void, /* Return type */
|
| 118 |
+
ProcessGroup, /* Parent class */
|
| 119 |
+
abort, /* Name of function in C++ */
|
| 120 |
+
);
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
const std::string& getGroupName() const override {
|
| 124 |
+
PYBIND11_OVERRIDE(
|
| 125 |
+
const std::string&, /* Return type */
|
| 126 |
+
ProcessGroup, /* Parent class */
|
| 127 |
+
getGroupName, /* Name of function in C++ */
|
| 128 |
+
);
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
void setGroupName(const std::string& group_name) override {
|
| 132 |
+
PYBIND11_OVERRIDE(
|
| 133 |
+
void, /* Return type */
|
| 134 |
+
ProcessGroup, /* Parent class */
|
| 135 |
+
setGroupName, /* Name of function in C++ */
|
| 136 |
+
group_name);
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
const std::string& getGroupDesc() const override {
|
| 140 |
+
PYBIND11_OVERRIDE(
|
| 141 |
+
const std::string&, /* Return type */
|
| 142 |
+
ProcessGroup, /* Parent class */
|
| 143 |
+
getGroupDesc, /* Name of function in C++ */
|
| 144 |
+
);
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
void setGroupDesc(const std::string& group_desc) override {
|
| 148 |
+
PYBIND11_OVERRIDE(
|
| 149 |
+
void, /* Return type */
|
| 150 |
+
ProcessGroup, /* Parent class */
|
| 151 |
+
setGroupDesc, /* Name of function in C++ */
|
| 152 |
+
group_desc);
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
c10::intrusive_ptr<ProcessGroup> splitGroup(
|
| 156 |
+
const std::vector<int>& ranks,
|
| 157 |
+
const std::optional<std::chrono::milliseconds>& timeout,
|
| 158 |
+
const std::optional<c10::intrusive_ptr<Backend::Options>>& opts,
|
| 159 |
+
const std::optional<std::string>& group_name,
|
| 160 |
+
const std::optional<std::string>& group_desc) override {
|
| 161 |
+
PYBIND11_OVERRIDE(
|
| 162 |
+
c10::intrusive_ptr<ProcessGroup>, /* Return type */
|
| 163 |
+
ProcessGroup, /* Parent class */
|
| 164 |
+
splitGroup, /* Name of function in C++ */
|
| 165 |
+
ranks,
|
| 166 |
+
timeout,
|
| 167 |
+
opts,
|
| 168 |
+
group_name,
|
| 169 |
+
group_desc);
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
c10::intrusive_ptr<ProcessGroup> mergeRemoteGroup(
|
| 173 |
+
const c10::intrusive_ptr<c10d::Store>& store,
|
| 174 |
+
const MergeOptions& opts,
|
| 175 |
+
const int& size) override {
|
| 176 |
+
PYBIND11_OVERRIDE(
|
| 177 |
+
c10::intrusive_ptr<ProcessGroup>, /* Return type */
|
| 178 |
+
ProcessGroup, /* Parent class */
|
| 179 |
+
mergeRemoteGroup, /* Name of function in C++ */
|
| 180 |
+
store,
|
| 181 |
+
opts,
|
| 182 |
+
size);
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
c10::intrusive_ptr<Work> allgather(
|
| 186 |
+
std::vector<std::vector<at::Tensor>>& outputTensors,
|
| 187 |
+
std::vector<at::Tensor>& inputTensors,
|
| 188 |
+
const AllgatherOptions& opts = AllgatherOptions()) override {
|
| 189 |
+
WORK_OVERRIDE(
|
| 190 |
+
ProcessGroup, /* Parent class */
|
| 191 |
+
allgather, /* Name of function in C++ */
|
| 192 |
+
outputTensors,
|
| 193 |
+
inputTensors,
|
| 194 |
+
opts);
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
c10::intrusive_ptr<Work> allgather_into_tensor_coalesced(
|
| 198 |
+
std::vector<at::Tensor>& outputTensors,
|
| 199 |
+
std::vector<at::Tensor>& inputTensors,
|
| 200 |
+
const AllgatherOptions& opts = AllgatherOptions()) override {
|
| 201 |
+
WORK_OVERRIDE(
|
| 202 |
+
ProcessGroup, /* Parent class */
|
| 203 |
+
allgather_into_tensor_coalesced, /* Name of function in C++ */
|
| 204 |
+
outputTensors,
|
| 205 |
+
inputTensors,
|
| 206 |
+
opts);
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
c10::intrusive_ptr<Work> allreduce(
|
| 210 |
+
std::vector<at::Tensor>& tensors,
|
| 211 |
+
const AllreduceOptions& opts = AllreduceOptions()) override {
|
| 212 |
+
WORK_OVERRIDE(
|
| 213 |
+
// py::object, /* Return type */
|
| 214 |
+
ProcessGroup, /* Parent class */
|
| 215 |
+
allreduce, /* Name of function in C++ */
|
| 216 |
+
tensors,
|
| 217 |
+
opts);
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
c10::intrusive_ptr<Work> allreduce_coalesced(
|
| 221 |
+
std::vector<at::Tensor>& tensors,
|
| 222 |
+
const AllreduceCoalescedOptions& opts =
|
| 223 |
+
AllreduceCoalescedOptions()) override {
|
| 224 |
+
WORK_OVERRIDE(
|
| 225 |
+
ProcessGroup, /* Parent class */
|
| 226 |
+
allreduce_coalesced, /* Name of function in C++ */
|
| 227 |
+
tensors,
|
| 228 |
+
opts);
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
c10::intrusive_ptr<Work> alltoall_base(
|
| 232 |
+
at::Tensor& outputBuffer,
|
| 233 |
+
at::Tensor& inputBuffer,
|
| 234 |
+
std::vector<int64_t>& outputSplitSizes,
|
| 235 |
+
std::vector<int64_t>& inputSplitSizes,
|
| 236 |
+
const AllToAllOptions& opts = AllToAllOptions()) override {
|
| 237 |
+
WORK_OVERRIDE(
|
| 238 |
+
ProcessGroup, /* Parent class */
|
| 239 |
+
alltoall_base, /* Name of function in C++ */
|
| 240 |
+
outputBuffer,
|
| 241 |
+
inputBuffer,
|
| 242 |
+
outputSplitSizes,
|
| 243 |
+
inputSplitSizes,
|
| 244 |
+
opts);
|
| 245 |
+
}
|
| 246 |
+
|
| 247 |
+
c10::intrusive_ptr<Work> barrier(
|
| 248 |
+
const BarrierOptions& opts = BarrierOptions()) override {
|
| 249 |
+
WORK_OVERRIDE(
|
| 250 |
+
ProcessGroup, /* Parent class */
|
| 251 |
+
barrier, /* Name of function in C++ */
|
| 252 |
+
opts);
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
c10::intrusive_ptr<Work> broadcast(
|
| 256 |
+
std::vector<at::Tensor>& tensors,
|
| 257 |
+
const BroadcastOptions& opts = BroadcastOptions()) override {
|
| 258 |
+
WORK_OVERRIDE(
|
| 259 |
+
ProcessGroup, /* Parent class */
|
| 260 |
+
broadcast, /* Name of function in C++ */
|
| 261 |
+
tensors,
|
| 262 |
+
opts);
|
| 263 |
+
}
|
| 264 |
+
|
| 265 |
+
c10::intrusive_ptr<Work> reduce_scatter(
|
| 266 |
+
std::vector<at::Tensor>& outputTensors,
|
| 267 |
+
std::vector<std::vector<at::Tensor>>& inputTensors,
|
| 268 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override {
|
| 269 |
+
WORK_OVERRIDE(
|
| 270 |
+
ProcessGroup, /* Parent class */
|
| 271 |
+
reduce_scatter, /* Name of function in C++ */
|
| 272 |
+
outputTensors,
|
| 273 |
+
inputTensors,
|
| 274 |
+
opts);
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
c10::intrusive_ptr<Work> reduce_scatter_tensor_coalesced(
|
| 278 |
+
std::vector<at::Tensor>& outputTensors,
|
| 279 |
+
std::vector<at::Tensor>& inputTensors,
|
| 280 |
+
const ReduceScatterOptions& opts = ReduceScatterOptions()) override {
|
| 281 |
+
WORK_OVERRIDE(
|
| 282 |
+
ProcessGroup, /* Parent class */
|
| 283 |
+
reduce_scatter_tensor_coalesced, /* Name of function in C++ */
|
| 284 |
+
outputTensors,
|
| 285 |
+
inputTensors,
|
| 286 |
+
opts);
|
| 287 |
+
}
|
| 288 |
+
|
| 289 |
+
c10::intrusive_ptr<Work> send(
|
| 290 |
+
std::vector<at::Tensor>& tensors,
|
| 291 |
+
int dstRank,
|
| 292 |
+
int tag) override {
|
| 293 |
+
WORK_OVERRIDE(
|
| 294 |
+
ProcessGroup, /* Parent class */
|
| 295 |
+
send, /* Name of function in C++ */
|
| 296 |
+
tensors,
|
| 297 |
+
dstRank,
|
| 298 |
+
tag);
|
| 299 |
+
}
|
| 300 |
+
|
| 301 |
+
c10::intrusive_ptr<Work> recv(
|
| 302 |
+
std::vector<at::Tensor>& tensors,
|
| 303 |
+
int srcRank,
|
| 304 |
+
int tag) override {
|
| 305 |
+
WORK_OVERRIDE(
|
| 306 |
+
ProcessGroup, /* Parent class */
|
| 307 |
+
recv, /* Name of function in C++ */
|
| 308 |
+
tensors,
|
| 309 |
+
srcRank,
|
| 310 |
+
tag);
|
| 311 |
+
}
|
| 312 |
+
};
|
| 313 |
+
|
| 314 |
+
class TORCH_PYTHON_API PythonOnCompletionHook {
|
| 315 |
+
public:
|
| 316 |
+
// Wraps a py::object hook and acquires Python GIL in dtor before
|
| 317 |
+
// destructing the hook object.
|
| 318 |
+
PythonOnCompletionHook(py::object hook) : hook_(std::move(hook)) {}
|
| 319 |
+
PythonOnCompletionHook(const PythonOnCompletionHook&) = default;
|
| 320 |
+
|
| 321 |
+
// NOLINTNEXTLINE(bugprone-exception-escape)
|
| 322 |
+
~PythonOnCompletionHook() {
|
| 323 |
+
py::gil_scoped_acquire ag;
|
| 324 |
+
hook_.dec_ref();
|
| 325 |
+
// Explicitly set hook_ to nullptr to prevent py::object's dtor
|
| 326 |
+
// to decref on the PyObject again.
|
| 327 |
+
// See Note [Destructing py::object] in python_ivalue.h
|
| 328 |
+
hook_.ptr() = nullptr;
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
void operator()(const std::shared_ptr<WorkInfo>& workInfo) const {
|
| 332 |
+
std::exception_ptr eptr;
|
| 333 |
+
{
|
| 334 |
+
py::gil_scoped_acquire acquire;
|
| 335 |
+
try {
|
| 336 |
+
hook_(workInfo);
|
| 337 |
+
} catch (py::error_already_set& e) {
|
| 338 |
+
// py::error_already_set requires GIL to destruct, take
|
| 339 |
+
// special care.
|
| 340 |
+
eptr = std::make_exception_ptr(std::runtime_error(e.what()));
|
| 341 |
+
e.restore();
|
| 342 |
+
PyErr_Clear();
|
| 343 |
+
} catch (std::exception&) {
|
| 344 |
+
eptr = std::current_exception();
|
| 345 |
+
}
|
| 346 |
+
}
|
| 347 |
+
// No more Python-related stuff at this point, i.e., this
|
| 348 |
+
// exception can be captured and handled by PG backend.
|
| 349 |
+
if (eptr)
|
| 350 |
+
std::rethrow_exception(eptr);
|
| 351 |
+
}
|
| 352 |
+
|
| 353 |
+
private:
|
| 354 |
+
py::object hook_;
|
| 355 |
+
};
|
| 356 |
+
|
| 357 |
+
} // namespace c10d
|
| 358 |
+
|
| 359 |
+
#else
|
| 360 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 361 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/RankLocal.hpp
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
|
| 3 |
+
#pragma once
|
| 4 |
+
|
| 5 |
+
#include <shared_mutex>
|
| 6 |
+
|
| 7 |
+
#include <torch/csrc/autograd/function.h>
|
| 8 |
+
|
| 9 |
+
namespace c10d {
|
| 10 |
+
|
| 11 |
+
// `RankLocal` maintains a unique instance of T for each non-autograd thread.
|
| 12 |
+
// For non-autograd threads, `RankLocal<T>::get()` functions similar to
|
| 13 |
+
// thread_local. For autograd threads, `RankLocal<T>::get()` returns the
|
| 14 |
+
// instance of T corresponding to the enqueuing non-autograd thread. The
|
| 15 |
+
// mechanism allows for rank-specific context shared between forward and
|
| 16 |
+
// backward. It works for both the one-rank-per-process and one-rank-per-thread
|
| 17 |
+
// scenarios.
|
| 18 |
+
//
|
| 19 |
+
// NOTE: RankLocal doesn't make the underlying objects thread-safe.
|
| 20 |
+
template <typename T>
|
| 21 |
+
class RankLocal {
|
| 22 |
+
public:
|
| 23 |
+
RankLocal(const RankLocal&) = delete;
|
| 24 |
+
RankLocal& operator=(const RankLocal&) = delete;
|
| 25 |
+
|
| 26 |
+
static T& get() {
|
| 27 |
+
// Fast path: non-autograd threads can simply return
|
| 28 |
+
// the object reference cached in TLS.
|
| 29 |
+
if (cached_ != nullptr) {
|
| 30 |
+
return *cached_;
|
| 31 |
+
}
|
| 32 |
+
const auto node = torch::autograd::get_current_node();
|
| 33 |
+
auto fwd_thread_id = node == nullptr ? at::RecordFunction::currentThreadId()
|
| 34 |
+
: node->thread_id();
|
| 35 |
+
// Optimistically acquire the read lock first, since most likely we are in
|
| 36 |
+
// an autograd thread and the object has already been constructed.
|
| 37 |
+
{
|
| 38 |
+
std::shared_lock read_lock(lock_);
|
| 39 |
+
auto it = thread_id_to_rank_local_.find(fwd_thread_id);
|
| 40 |
+
if (it != thread_id_to_rank_local_.end()) {
|
| 41 |
+
// Cache for non-autograd threads
|
| 42 |
+
if (node == nullptr) {
|
| 43 |
+
cached_ = &it->second;
|
| 44 |
+
}
|
| 45 |
+
return it->second;
|
| 46 |
+
}
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
std::unique_lock write_lock(lock_);
|
| 50 |
+
auto [it, _] = thread_id_to_rank_local_.try_emplace(fwd_thread_id);
|
| 51 |
+
// Cache for non-autograd threads
|
| 52 |
+
if (node == nullptr) {
|
| 53 |
+
cached_ = &it->second;
|
| 54 |
+
}
|
| 55 |
+
return it->second;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
// Apply a function to all thread-local instances and return the first
|
| 59 |
+
// non-empty result. This is useful for cross-thread lookups when we need
|
| 60 |
+
// to find data that may have been registered on a different thread.
|
| 61 |
+
// The function should have signature: std::optional<R>(T&)
|
| 62 |
+
template <typename F>
|
| 63 |
+
static auto find_across_all(F&& func) -> decltype(func(std::declval<T&>())) {
|
| 64 |
+
std::shared_lock read_lock(lock_);
|
| 65 |
+
for (auto& [thread_id, instance] : thread_id_to_rank_local_) {
|
| 66 |
+
auto result = func(instance);
|
| 67 |
+
if (result) {
|
| 68 |
+
return result;
|
| 69 |
+
}
|
| 70 |
+
}
|
| 71 |
+
return decltype(func(std::declval<T&>()))();
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
private:
|
| 75 |
+
RankLocal() = default;
|
| 76 |
+
thread_local static T* cached_;
|
| 77 |
+
static std::unordered_map<uint64_t, T> thread_id_to_rank_local_;
|
| 78 |
+
static std::shared_mutex lock_;
|
| 79 |
+
};
|
| 80 |
+
|
| 81 |
+
template <typename T>
|
| 82 |
+
thread_local T* RankLocal<T>::cached_ = nullptr;
|
| 83 |
+
|
| 84 |
+
template <typename T>
|
| 85 |
+
std::unordered_map<uint64_t, T> RankLocal<T>::thread_id_to_rank_local_;
|
| 86 |
+
|
| 87 |
+
template <typename T>
|
| 88 |
+
std::shared_mutex RankLocal<T>::lock_;
|
| 89 |
+
|
| 90 |
+
} // namespace c10d
|
| 91 |
+
|
| 92 |
+
#else
|
| 93 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 94 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Store.hpp
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <chrono>
|
| 5 |
+
#include <cstdint>
|
| 6 |
+
#include <string>
|
| 7 |
+
#include <vector>
|
| 8 |
+
|
| 9 |
+
#include <c10/macros/Macros.h>
|
| 10 |
+
#include <torch/custom_class.h>
|
| 11 |
+
|
| 12 |
+
namespace c10d {
|
| 13 |
+
|
| 14 |
+
// callback function will be given arguments (std::optional<string> oldValue,
|
| 15 |
+
// std::optional<string> newValue)
|
| 16 |
+
using WatchKeyCallback =
|
| 17 |
+
std::function<void(std::optional<std::string>, std::optional<std::string>)>;
|
| 18 |
+
|
| 19 |
+
class TORCH_API Store : public torch::CustomClassHolder {
|
| 20 |
+
public:
|
| 21 |
+
static constexpr std::chrono::milliseconds kDefaultTimeout =
|
| 22 |
+
std::chrono::seconds(300);
|
| 23 |
+
static constexpr std::chrono::milliseconds kNoTimeout =
|
| 24 |
+
std::chrono::milliseconds::zero();
|
| 25 |
+
|
| 26 |
+
Store() : timeout_(kDefaultTimeout) {}
|
| 27 |
+
|
| 28 |
+
explicit Store(const std::chrono::milliseconds& timeout)
|
| 29 |
+
: timeout_(timeout) {}
|
| 30 |
+
|
| 31 |
+
Store(const Store&) = default;
|
| 32 |
+
Store(Store&&) noexcept = default;
|
| 33 |
+
|
| 34 |
+
~Store() override = default;
|
| 35 |
+
|
| 36 |
+
// Clone a thread safe copy of this store object that points to the same
|
| 37 |
+
// underlying store.
|
| 38 |
+
virtual c10::intrusive_ptr<Store> clone() = 0;
|
| 39 |
+
|
| 40 |
+
void set(const std::string& key, const std::string& value);
|
| 41 |
+
|
| 42 |
+
virtual void set(
|
| 43 |
+
const std::string& key,
|
| 44 |
+
const std::vector<uint8_t>& value) = 0;
|
| 45 |
+
|
| 46 |
+
std::string compareSet(
|
| 47 |
+
const std::string& key,
|
| 48 |
+
const std::string& currentValue,
|
| 49 |
+
const std::string& newValue);
|
| 50 |
+
|
| 51 |
+
virtual std::vector<uint8_t> compareSet(
|
| 52 |
+
const std::string& key,
|
| 53 |
+
const std::vector<uint8_t>& currentValue,
|
| 54 |
+
const std::vector<uint8_t>& newValue) {
|
| 55 |
+
C10_THROW_ERROR(NotImplementedError, "Not implemented.");
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
std::string get_to_str(const std::string& key);
|
| 59 |
+
|
| 60 |
+
virtual std::vector<uint8_t> get(const std::string& key) = 0;
|
| 61 |
+
|
| 62 |
+
virtual int64_t add(const std::string& key, int64_t value) = 0;
|
| 63 |
+
|
| 64 |
+
virtual bool deleteKey(const std::string& key) = 0;
|
| 65 |
+
|
| 66 |
+
virtual bool check(const std::vector<std::string>& keys) = 0;
|
| 67 |
+
|
| 68 |
+
virtual int64_t getNumKeys() = 0;
|
| 69 |
+
|
| 70 |
+
virtual void wait(const std::vector<std::string>& keys) = 0;
|
| 71 |
+
|
| 72 |
+
virtual void wait(
|
| 73 |
+
const std::vector<std::string>& keys,
|
| 74 |
+
const std::chrono::milliseconds& timeout) = 0;
|
| 75 |
+
|
| 76 |
+
virtual const std::chrono::milliseconds& getTimeout() const noexcept;
|
| 77 |
+
|
| 78 |
+
virtual void setTimeout(const std::chrono::milliseconds& timeout);
|
| 79 |
+
|
| 80 |
+
// watchKey() is deprecated and no longer supported.
|
| 81 |
+
virtual void watchKey(
|
| 82 |
+
const std::string& /* unused */,
|
| 83 |
+
// NOLINTNEXTLINE(performance-unnecessary-value-param)
|
| 84 |
+
WatchKeyCallback /* unused */) {
|
| 85 |
+
C10_THROW_ERROR(
|
| 86 |
+
NotImplementedError,
|
| 87 |
+
"watchKey is deprecated, no implementation support it.");
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
virtual void append(
|
| 91 |
+
const std::string& key,
|
| 92 |
+
const std::vector<uint8_t>& value);
|
| 93 |
+
|
| 94 |
+
virtual std::vector<std::vector<uint8_t>> multiGet(
|
| 95 |
+
const std::vector<std::string>& keys);
|
| 96 |
+
|
| 97 |
+
virtual void multiSet(
|
| 98 |
+
const std::vector<std::string>& keys,
|
| 99 |
+
const std::vector<std::vector<uint8_t>>& values);
|
| 100 |
+
|
| 101 |
+
// Returns true if this store support append, multiGet and multiSet
|
| 102 |
+
virtual bool hasExtendedApi() const;
|
| 103 |
+
|
| 104 |
+
virtual void queuePush(
|
| 105 |
+
const std::string& key,
|
| 106 |
+
const std::vector<uint8_t>& value) {
|
| 107 |
+
C10_THROW_ERROR(NotImplementedError, "queue support is not implemented.");
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
virtual std::vector<uint8_t> queuePop(const std::string& key, bool block) {
|
| 111 |
+
C10_THROW_ERROR(NotImplementedError, "queue support is not implemented.");
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
virtual int64_t queueLen(const std::string& key) {
|
| 115 |
+
C10_THROW_ERROR(NotImplementedError, "queue support is not implemented.");
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
virtual std::vector<std::string> listKeys() {
|
| 119 |
+
C10_THROW_ERROR(
|
| 120 |
+
NotImplementedError, "listKeys support is not implemented.");
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
// Barrier operation that blocks until world_size workers have reached it.
|
| 124 |
+
// This is an optimized operation that combines increment and wait into a
|
| 125 |
+
// single operation, reducing network round trips compared to using
|
| 126 |
+
// separate add() and wait() calls.
|
| 127 |
+
virtual void barrier(
|
| 128 |
+
const std::string& key,
|
| 129 |
+
int64_t world_size,
|
| 130 |
+
const std::chrono::milliseconds& timeout);
|
| 131 |
+
|
| 132 |
+
void barrier(const std::string& key, int64_t world_size) {
|
| 133 |
+
barrier(key, world_size, timeout_);
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
protected:
|
| 137 |
+
std::chrono::milliseconds timeout_;
|
| 138 |
+
};
|
| 139 |
+
|
| 140 |
+
/*
|
| 141 |
+
StoreTimeoutGuard is a RAII guard that will set the store timeout and restore it
|
| 142 |
+
when it returns.
|
| 143 |
+
*/
|
| 144 |
+
class StoreTimeoutGuard {
|
| 145 |
+
public:
|
| 146 |
+
explicit StoreTimeoutGuard(
|
| 147 |
+
Store& store,
|
| 148 |
+
const std::chrono::milliseconds& timeout)
|
| 149 |
+
: store_(store), oldTimeout_(store.getTimeout()) {
|
| 150 |
+
store.setTimeout(timeout);
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
~StoreTimeoutGuard() {
|
| 154 |
+
store_.setTimeout(oldTimeout_);
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
/* Disabling copy and move semantics */
|
| 158 |
+
StoreTimeoutGuard(const StoreTimeoutGuard&) = delete;
|
| 159 |
+
StoreTimeoutGuard& operator=(const StoreTimeoutGuard&) = delete;
|
| 160 |
+
StoreTimeoutGuard(StoreTimeoutGuard&&) = delete;
|
| 161 |
+
StoreTimeoutGuard& operator=(StoreTimeoutGuard&&) = delete;
|
| 162 |
+
|
| 163 |
+
private:
|
| 164 |
+
Store& store_;
|
| 165 |
+
std::chrono::milliseconds oldTimeout_{};
|
| 166 |
+
};
|
| 167 |
+
|
| 168 |
+
} // namespace c10d
|
| 169 |
+
|
| 170 |
+
#else
|
| 171 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 172 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/TCPStore.hpp
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <cstddef>
|
| 5 |
+
#include <cstdint>
|
| 6 |
+
#include <memory>
|
| 7 |
+
|
| 8 |
+
#include <torch/csrc/distributed/c10d/Store.hpp>
|
| 9 |
+
|
| 10 |
+
namespace c10d {
|
| 11 |
+
namespace detail {
|
| 12 |
+
|
| 13 |
+
// TCPStore is a key-value store used by PyTorch mainly for distributed
|
| 14 |
+
// rendezvous, but for other purposes as well. (e.g., a centralized storage for
|
| 15 |
+
// synchronization among different processes.)
|
| 16 |
+
//
|
| 17 |
+
// It is run via a classic client-server architecture, where the server runs
|
| 18 |
+
// a separate background thread (alternatively we call it daemon thread). The
|
| 19 |
+
// client and server communicate via TCP sockets.
|
| 20 |
+
//
|
| 21 |
+
// Currently we have two types of server backends:
|
| 22 |
+
// 1. TCPStoreBackend: a single thread to handle all incoming request
|
| 23 |
+
// synchronously.
|
| 24 |
+
// 2. LibUVTCPStoreBackend: an event-driven asynchronous stream processing that
|
| 25 |
+
// leverages libuv library (https://github.com/libuv/libuv) for better
|
| 26 |
+
// performance. And this backend now is recommended to users. (We set the
|
| 27 |
+
// default value of `useLibUV` inside `TCPStoreOptions` to true now, so users
|
| 28 |
+
// should get it by default).
|
| 29 |
+
//
|
| 30 |
+
// Code structure:
|
| 31 |
+
// ├── TCPStore client side API and server setup code:
|
| 32 |
+
// │ TCPStore.hpp/TCPStore.cpp
|
| 33 |
+
// ├── TCPStoreBackend server side API implementation code:
|
| 34 |
+
// │ TCPStoreBackend.hpp/TCPStoreBackend.cpp
|
| 35 |
+
// | (actual class:`TCPStoreMasterDaemon`)
|
| 36 |
+
// ├── LibUVTCPStoreBackend
|
| 37 |
+
// │ TCPStoreLibUvBackend.cpp
|
| 38 |
+
// | (actual class: `LibUVStoreDaemon`)
|
| 39 |
+
|
| 40 |
+
class TCPServer;
|
| 41 |
+
|
| 42 |
+
class TCPClient;
|
| 43 |
+
|
| 44 |
+
struct SocketAddress {
|
| 45 |
+
std::string host;
|
| 46 |
+
std::uint16_t port{};
|
| 47 |
+
};
|
| 48 |
+
|
| 49 |
+
} // namespace detail
|
| 50 |
+
|
| 51 |
+
struct TCPStoreOptions {
|
| 52 |
+
static constexpr std::uint16_t kDefaultPort = 29500;
|
| 53 |
+
|
| 54 |
+
std::uint16_t port = kDefaultPort;
|
| 55 |
+
bool isServer = false;
|
| 56 |
+
std::optional<std::size_t> numWorkers = std::nullopt;
|
| 57 |
+
bool waitWorkers = true;
|
| 58 |
+
std::chrono::milliseconds timeout = Store::kDefaultTimeout;
|
| 59 |
+
|
| 60 |
+
// A boolean value indicating whether multiple store instances can be
|
| 61 |
+
// initialized with the same host:port pair.
|
| 62 |
+
bool multiTenant = false;
|
| 63 |
+
|
| 64 |
+
// If specified, and if isServer is true, the underlying TCPServer will take
|
| 65 |
+
// over the bound socket associated to this fd. This option is useful to avoid
|
| 66 |
+
// port assignment races in certain scenarios.
|
| 67 |
+
std::optional<int> masterListenFd = std::nullopt;
|
| 68 |
+
|
| 69 |
+
// A boolean value indicating whether to use the experimental libUV backend.
|
| 70 |
+
bool useLibUV = true;
|
| 71 |
+
};
|
| 72 |
+
|
| 73 |
+
class TORCH_API TCPStore : public Store {
|
| 74 |
+
public:
|
| 75 |
+
static constexpr std::chrono::milliseconds kConnectRetryDelay{1000};
|
| 76 |
+
|
| 77 |
+
explicit TCPStore(std::string host, const TCPStoreOptions& opts = {});
|
| 78 |
+
|
| 79 |
+
~TCPStore() override;
|
| 80 |
+
|
| 81 |
+
c10::intrusive_ptr<Store> clone() override;
|
| 82 |
+
|
| 83 |
+
void set(const std::string& key, const std::vector<uint8_t>& value) override;
|
| 84 |
+
|
| 85 |
+
std::vector<uint8_t> compareSet(
|
| 86 |
+
const std::string& key,
|
| 87 |
+
const std::vector<uint8_t>& expectedValue,
|
| 88 |
+
const std::vector<uint8_t>& desiredValue) override;
|
| 89 |
+
|
| 90 |
+
std::vector<uint8_t> get(const std::string& key) override;
|
| 91 |
+
|
| 92 |
+
int64_t add(const std::string& key, int64_t value) override;
|
| 93 |
+
|
| 94 |
+
bool deleteKey(const std::string& key) override;
|
| 95 |
+
|
| 96 |
+
bool check(const std::vector<std::string>& keys) override;
|
| 97 |
+
|
| 98 |
+
int64_t getNumKeys() override;
|
| 99 |
+
|
| 100 |
+
void wait(const std::vector<std::string>& keys) override;
|
| 101 |
+
|
| 102 |
+
void wait(
|
| 103 |
+
const std::vector<std::string>& keys,
|
| 104 |
+
const std::chrono::milliseconds& timeout) override;
|
| 105 |
+
|
| 106 |
+
void append(const std::string& key, const std::vector<uint8_t>& value)
|
| 107 |
+
override;
|
| 108 |
+
|
| 109 |
+
std::vector<std::vector<uint8_t>> multiGet(
|
| 110 |
+
const std::vector<std::string>& keys) override;
|
| 111 |
+
|
| 112 |
+
void multiSet(
|
| 113 |
+
const std::vector<std::string>& keys,
|
| 114 |
+
const std::vector<std::vector<uint8_t>>& values) override;
|
| 115 |
+
|
| 116 |
+
bool hasExtendedApi() const override;
|
| 117 |
+
|
| 118 |
+
void queuePush(const std::string& key, const std::vector<uint8_t>& value)
|
| 119 |
+
override;
|
| 120 |
+
|
| 121 |
+
std::vector<uint8_t> queuePop(const std::string& key, bool block) override;
|
| 122 |
+
|
| 123 |
+
int64_t queueLen(const std::string& key) override;
|
| 124 |
+
|
| 125 |
+
std::vector<std::string> listKeys() override;
|
| 126 |
+
|
| 127 |
+
void barrier(
|
| 128 |
+
const std::string& key,
|
| 129 |
+
int64_t world_size,
|
| 130 |
+
const std::chrono::milliseconds& timeout) override;
|
| 131 |
+
|
| 132 |
+
// Waits for all workers to join.
|
| 133 |
+
void waitForWorkers();
|
| 134 |
+
|
| 135 |
+
// Returns the hostname used by the TCPStore.
|
| 136 |
+
const std::string& getHost() const noexcept {
|
| 137 |
+
return addr_.host;
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
// Returns the port used by the TCPStore.
|
| 141 |
+
std::uint16_t getPort() const noexcept {
|
| 142 |
+
return addr_.port;
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
bool isLibUvBackend() const noexcept {
|
| 146 |
+
return usingLibUv_;
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
// note(xilunwu): this function is only for internal testing
|
| 150 |
+
void _splitSet(const std::string& key, const std::vector<uint8_t>& data);
|
| 151 |
+
|
| 152 |
+
std::string repr() const;
|
| 153 |
+
|
| 154 |
+
private:
|
| 155 |
+
int64_t incrementValueBy(const std::string& key, int64_t delta);
|
| 156 |
+
|
| 157 |
+
void ping();
|
| 158 |
+
void validate();
|
| 159 |
+
|
| 160 |
+
std::vector<uint8_t> doGet(const std::string& key);
|
| 161 |
+
|
| 162 |
+
void doWait(
|
| 163 |
+
c10::ArrayRef<std::string> keys,
|
| 164 |
+
std::chrono::milliseconds timeout);
|
| 165 |
+
|
| 166 |
+
detail::SocketAddress addr_;
|
| 167 |
+
std::shared_ptr<detail::TCPServer> server_;
|
| 168 |
+
std::unique_ptr<detail::TCPClient> client_;
|
| 169 |
+
std::optional<std::size_t> numWorkers_;
|
| 170 |
+
|
| 171 |
+
const std::string initKey_ = "init/";
|
| 172 |
+
const std::string keyPrefix_ = "/";
|
| 173 |
+
std::mutex activeOpLock_;
|
| 174 |
+
bool usingLibUv_ = true;
|
| 175 |
+
};
|
| 176 |
+
|
| 177 |
+
} // namespace c10d
|
| 178 |
+
|
| 179 |
+
#else
|
| 180 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 181 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/TCPStoreBackend.hpp
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <thread>
|
| 5 |
+
|
| 6 |
+
#include <torch/csrc/distributed/c10d/TCPStore.hpp>
|
| 7 |
+
#include <torch/csrc/distributed/c10d/socket.h>
|
| 8 |
+
|
| 9 |
+
#ifdef _WIN32
|
| 10 |
+
#include <io.h>
|
| 11 |
+
#include <winsock2.h>
|
| 12 |
+
#else
|
| 13 |
+
#include <poll.h>
|
| 14 |
+
#include <unistd.h>
|
| 15 |
+
#endif
|
| 16 |
+
|
| 17 |
+
namespace c10d::detail {
|
| 18 |
+
|
| 19 |
+
// Magic number for client validation.
|
| 20 |
+
static const uint32_t validationMagicNumber = 0x3C85F7CE;
|
| 21 |
+
|
| 22 |
+
enum class QueryType : uint8_t {
|
| 23 |
+
VALIDATE,
|
| 24 |
+
SET,
|
| 25 |
+
COMPARE_SET,
|
| 26 |
+
GET,
|
| 27 |
+
ADD,
|
| 28 |
+
CHECK,
|
| 29 |
+
WAIT,
|
| 30 |
+
GETNUMKEYS,
|
| 31 |
+
DELETE_KEY,
|
| 32 |
+
APPEND,
|
| 33 |
+
MULTI_GET,
|
| 34 |
+
MULTI_SET,
|
| 35 |
+
CANCEL_WAIT,
|
| 36 |
+
PING,
|
| 37 |
+
QUEUE_PUSH,
|
| 38 |
+
QUEUE_POP,
|
| 39 |
+
QUEUE_LEN,
|
| 40 |
+
LIST_KEYS,
|
| 41 |
+
BARRIER,
|
| 42 |
+
};
|
| 43 |
+
|
| 44 |
+
enum class CheckResponseType : uint8_t { READY, NOT_READY };
|
| 45 |
+
|
| 46 |
+
enum class WaitResponseType : uint8_t { STOP_WAITING, WAIT_CANCELED };
|
| 47 |
+
|
| 48 |
+
// Abstract base class to handle thread state for TCPStoreMasterDaemon.
|
| 49 |
+
// Contains the windows/unix implementations to signal a
|
| 50 |
+
// shutdown sequence for the thread
|
| 51 |
+
class BackgroundThread {
|
| 52 |
+
public:
|
| 53 |
+
explicit BackgroundThread();
|
| 54 |
+
|
| 55 |
+
virtual ~BackgroundThread() = 0;
|
| 56 |
+
virtual std::uint16_t port() const = 0;
|
| 57 |
+
|
| 58 |
+
void start();
|
| 59 |
+
bool stop_requested();
|
| 60 |
+
|
| 61 |
+
protected:
|
| 62 |
+
void dispose();
|
| 63 |
+
virtual void run() = 0;
|
| 64 |
+
virtual void stop() = 0;
|
| 65 |
+
bool is_running() {
|
| 66 |
+
return is_running_.load();
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
private:
|
| 70 |
+
std::atomic<bool> is_running_{false};
|
| 71 |
+
std::thread daemonThread_;
|
| 72 |
+
};
|
| 73 |
+
|
| 74 |
+
std::unique_ptr<BackgroundThread> create_tcpstore_backend(
|
| 75 |
+
const TCPStoreOptions& opts);
|
| 76 |
+
std::unique_ptr<BackgroundThread> create_libuv_tcpstore_backend(
|
| 77 |
+
const TCPStoreOptions& opts);
|
| 78 |
+
bool is_libuv_tcpstore_backend_available();
|
| 79 |
+
|
| 80 |
+
} // namespace c10d::detail
|
| 81 |
+
|
| 82 |
+
#else
|
| 83 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 84 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/TraceUtils.h
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
#include <c10/core/ScalarType.h>
|
| 4 |
+
#include <c10/util/ApproximateClock.h>
|
| 5 |
+
#include <c10/util/irange.h>
|
| 6 |
+
#include <torch/csrc/distributed/c10d/Store.hpp>
|
| 7 |
+
#include <torch/csrc/distributed/c10d/Types.hpp>
|
| 8 |
+
#include <torch/csrc/distributed/c10d/Utils.hpp>
|
| 9 |
+
#include <torch/csrc/jit/serialization/pickler.h>
|
| 10 |
+
#include <torch/csrc/profiler/combined_traceback.h>
|
| 11 |
+
|
| 12 |
+
#include <fmt/compile.h>
|
| 13 |
+
#include <fmt/core.h>
|
| 14 |
+
#include <fmt/ostream.h> // optional, for ostream fallback
|
| 15 |
+
#include <fmt/ranges.h> // for fmt::join
|
| 16 |
+
|
| 17 |
+
#include <sys/types.h>
|
| 18 |
+
#include <cstdlib>
|
| 19 |
+
#include <cstring>
|
| 20 |
+
#include <iterator>
|
| 21 |
+
#include <string>
|
| 22 |
+
#include <vector>
|
| 23 |
+
|
| 24 |
+
namespace c10d {
|
| 25 |
+
|
| 26 |
+
inline std::string getTraceStartKey(const std::string& pgName, int rank) {
|
| 27 |
+
return fmt::format(FMT_COMPILE("{}_{}_trace_start"), pgName, rank);
|
| 28 |
+
}
|
| 29 |
+
|
| 30 |
+
inline std::string getTraceEndKey(const std::string& pgName, int rank) {
|
| 31 |
+
return fmt::format(FMT_COMPILE("{}_{}_trace_end"), pgName, rank);
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
inline bool traceUpdate(
|
| 35 |
+
c10::intrusive_ptr<Store>& store,
|
| 36 |
+
const std::string& key,
|
| 37 |
+
uint64_t seq,
|
| 38 |
+
const std::string& col) {
|
| 39 |
+
std::vector<uint8_t> value(col.size() + sizeof(seq) + 1);
|
| 40 |
+
std::memcpy(value.data(), &seq, sizeof(seq));
|
| 41 |
+
std::memcpy(value.data() + sizeof(seq), col.data(), col.size());
|
| 42 |
+
try {
|
| 43 |
+
store->set(key, value);
|
| 44 |
+
return true;
|
| 45 |
+
} catch (...) {
|
| 46 |
+
LOG(ERROR) << "Store is down while updating #" << seq << " with key "
|
| 47 |
+
<< key;
|
| 48 |
+
return false;
|
| 49 |
+
}
|
| 50 |
+
return true;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
enum TraceDebugEvent {
|
| 54 |
+
kEventStart,
|
| 55 |
+
kEventEnd,
|
| 56 |
+
};
|
| 57 |
+
// <seq, <rank, <col, start/end>>>
|
| 58 |
+
using TraceMap =
|
| 59 |
+
std::map<uint64_t, std::map<int, std::pair<std::string, TraceDebugEvent>>>;
|
| 60 |
+
|
| 61 |
+
inline std::string ranksToString(const std::vector<int>& ranks) {
|
| 62 |
+
return fmt::to_string(fmt::join(ranks, ", "));
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
inline std::string ranksFromTrace(
|
| 66 |
+
const std::vector<std::pair<int, std::string>>& items) {
|
| 67 |
+
fmt::memory_buffer buf;
|
| 68 |
+
bool first = true;
|
| 69 |
+
for (const auto& [rank, _] : items) {
|
| 70 |
+
if (!first) {
|
| 71 |
+
fmt::format_to(std::back_inserter(buf), ", ");
|
| 72 |
+
}
|
| 73 |
+
fmt::format_to(std::back_inserter(buf), "{}", rank);
|
| 74 |
+
first = false;
|
| 75 |
+
}
|
| 76 |
+
return fmt::to_string(buf);
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
inline std::string analyzeMissingRanks(const std::vector<int>& missingRanks) {
|
| 80 |
+
return c10::str(
|
| 81 |
+
"\n\t - To our best knowledge, ranks [",
|
| 82 |
+
ranksToString(missingRanks),
|
| 83 |
+
"] are the lagging ranks that caused this timeout. "
|
| 84 |
+
"They never joined any collectives");
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
inline std::string analyzeLaggingRanks(const TraceMap& traceMap) {
|
| 88 |
+
uint64_t lagSeq = traceMap.begin()->first;
|
| 89 |
+
std::vector<int> startRanks;
|
| 90 |
+
std::vector<int> endRanks;
|
| 91 |
+
for (auto& p : traceMap.begin()->second) {
|
| 92 |
+
if (p.second.second == kEventStart) {
|
| 93 |
+
startRanks.push_back(p.first);
|
| 94 |
+
} else {
|
| 95 |
+
endRanks.push_back(p.first);
|
| 96 |
+
}
|
| 97 |
+
}
|
| 98 |
+
std::string report =
|
| 99 |
+
"\n\t - To our best knowledge, the lagging/dead/mismatched ranks "
|
| 100 |
+
"that caused the desync are:";
|
| 101 |
+
if (!startRanks.empty()) {
|
| 102 |
+
report += c10::str(
|
| 103 |
+
"\n\t - [",
|
| 104 |
+
ranksToString(startRanks),
|
| 105 |
+
"] joined but didn't finish collective #",
|
| 106 |
+
lagSeq,
|
| 107 |
+
" (count from 1)");
|
| 108 |
+
}
|
| 109 |
+
if (!endRanks.empty()) {
|
| 110 |
+
report += c10::str(
|
| 111 |
+
"\n\t [",
|
| 112 |
+
ranksToString(endRanks),
|
| 113 |
+
"] finished collective #",
|
| 114 |
+
lagSeq,
|
| 115 |
+
", but didn't join collective #",
|
| 116 |
+
lagSeq + 1,
|
| 117 |
+
" (count from 1)");
|
| 118 |
+
}
|
| 119 |
+
return report;
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
inline std::string dumpSnapshot(TraceMap& traceMap) {
|
| 123 |
+
std::string report = "\n\t - Snapshot of ranks' latest states:";
|
| 124 |
+
for (auto& tracePair : traceMap) {
|
| 125 |
+
uint64_t seq = tracePair.first;
|
| 126 |
+
std::map<int, std::pair<std::string, TraceDebugEvent>>& subMap =
|
| 127 |
+
tracePair.second;
|
| 128 |
+
|
| 129 |
+
std::unordered_map<std::string, std::vector<int>> collectivesStart;
|
| 130 |
+
std::unordered_map<std::string, std::vector<int>> collectivesEnd;
|
| 131 |
+
for (const auto& p : subMap) {
|
| 132 |
+
int rank = p.first;
|
| 133 |
+
const std::string& col = p.second.first;
|
| 134 |
+
if (p.second.second == kEventStart) {
|
| 135 |
+
collectivesStart[col].push_back(rank);
|
| 136 |
+
} else {
|
| 137 |
+
collectivesEnd[col].push_back(rank);
|
| 138 |
+
}
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
if (!collectivesStart.empty()) {
|
| 142 |
+
report += c10::str("\n\t #", seq, " started ranks:");
|
| 143 |
+
for (auto& mapPair : collectivesStart) {
|
| 144 |
+
report += c10::str(
|
| 145 |
+
"\n\t [",
|
| 146 |
+
ranksToString(mapPair.second),
|
| 147 |
+
"] started ",
|
| 148 |
+
mapPair.first);
|
| 149 |
+
}
|
| 150 |
+
}
|
| 151 |
+
if (!collectivesEnd.empty()) {
|
| 152 |
+
report += c10::str("\n\t #", seq, " finished ranks:");
|
| 153 |
+
for (auto& mapPair : collectivesEnd) {
|
| 154 |
+
report += c10::str(
|
| 155 |
+
"\n\t [",
|
| 156 |
+
ranksToString(mapPair.second),
|
| 157 |
+
"] finished ",
|
| 158 |
+
mapPair.first);
|
| 159 |
+
}
|
| 160 |
+
}
|
| 161 |
+
}
|
| 162 |
+
return report;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
inline bool parseTraceValue(
|
| 166 |
+
c10::intrusive_ptr<Store>& store,
|
| 167 |
+
const std::string& key,
|
| 168 |
+
uint64_t& seq,
|
| 169 |
+
std::string& col) {
|
| 170 |
+
try {
|
| 171 |
+
std::vector<uint8_t> traceValue = store->get(key);
|
| 172 |
+
std::memcpy(&seq, traceValue.data(), sizeof(seq));
|
| 173 |
+
std::string colName((char*)traceValue.data() + sizeof(seq));
|
| 174 |
+
col = colName;
|
| 175 |
+
return true;
|
| 176 |
+
} catch (...) {
|
| 177 |
+
LOG(ERROR) << "Store is down while getting key " << key;
|
| 178 |
+
return false;
|
| 179 |
+
}
|
| 180 |
+
return true;
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
inline std::string retrieveDesyncReport(
|
| 184 |
+
c10::intrusive_ptr<Store>& store,
|
| 185 |
+
const std::string& pgName,
|
| 186 |
+
int myRank,
|
| 187 |
+
int worldSize) {
|
| 188 |
+
std::string report;
|
| 189 |
+
|
| 190 |
+
uint64_t thisSeq = 0;
|
| 191 |
+
std::string thisCol;
|
| 192 |
+
|
| 193 |
+
std::vector<int> missingRanks;
|
| 194 |
+
TraceMap traceMap;
|
| 195 |
+
|
| 196 |
+
for (const auto rank : c10::irange(worldSize)) {
|
| 197 |
+
// Build traceMapStart.
|
| 198 |
+
uint64_t seqStart = 0;
|
| 199 |
+
{
|
| 200 |
+
std::string traceKeyStart = getTraceStartKey(pgName, rank);
|
| 201 |
+
if (!store->check({traceKeyStart})) {
|
| 202 |
+
missingRanks.push_back(rank);
|
| 203 |
+
continue;
|
| 204 |
+
}
|
| 205 |
+
std::string col;
|
| 206 |
+
if (!parseTraceValue(store, traceKeyStart, seqStart, col)) {
|
| 207 |
+
return report;
|
| 208 |
+
}
|
| 209 |
+
traceMap[seqStart].emplace(rank, std::make_pair(col, kEventStart));
|
| 210 |
+
if (rank == myRank) {
|
| 211 |
+
thisSeq = seqStart;
|
| 212 |
+
thisCol = std::move(col);
|
| 213 |
+
}
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
+
// Build traceMapEnd.
|
| 217 |
+
{
|
| 218 |
+
std::string traceKeyEnd = getTraceEndKey(pgName, rank);
|
| 219 |
+
if (!store->check({traceKeyEnd})) {
|
| 220 |
+
continue;
|
| 221 |
+
}
|
| 222 |
+
uint64_t seq = 0;
|
| 223 |
+
std::string col;
|
| 224 |
+
if (!parseTraceValue(store, traceKeyEnd, seq, col)) {
|
| 225 |
+
return report;
|
| 226 |
+
}
|
| 227 |
+
if (seq == seqStart) {
|
| 228 |
+
traceMap[seq][rank].second = kEventEnd;
|
| 229 |
+
}
|
| 230 |
+
}
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
TORCH_INTERNAL_ASSERT(
|
| 234 |
+
!missingRanks.empty() || !traceMap.empty(),
|
| 235 |
+
"Trace shouldn't be empty while enabled GLOO_ASYNC_TIMEOUT_DEBUG");
|
| 236 |
+
TORCH_INTERNAL_ASSERT(
|
| 237 |
+
!thisCol.empty(),
|
| 238 |
+
"Timeout rank [",
|
| 239 |
+
myRank,
|
| 240 |
+
"] must have collective tracking iteam in c10::Store trace");
|
| 241 |
+
TORCH_INTERNAL_ASSERT(
|
| 242 |
+
traceMap[thisSeq][myRank].second == kEventStart,
|
| 243 |
+
"Timeout rank [",
|
| 244 |
+
myRank,
|
| 245 |
+
"] last trace item must be kEventStart. thisSeq = ",
|
| 246 |
+
thisSeq,
|
| 247 |
+
", col = ",
|
| 248 |
+
thisCol);
|
| 249 |
+
|
| 250 |
+
report += c10::str(
|
| 251 |
+
"\n\t - [", myRank, "] Timeout at collective: ", thisCol, ", #", thisSeq);
|
| 252 |
+
|
| 253 |
+
if (!missingRanks.empty()) {
|
| 254 |
+
report += analyzeMissingRanks(missingRanks);
|
| 255 |
+
} else {
|
| 256 |
+
report += analyzeLaggingRanks(traceMap);
|
| 257 |
+
report += dumpSnapshot(traceMap);
|
| 258 |
+
}
|
| 259 |
+
|
| 260 |
+
return report;
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
inline std::string pickle_str(const c10::IValue& v) {
|
| 264 |
+
std::vector<char> result;
|
| 265 |
+
{
|
| 266 |
+
auto writer = [&](const char* data, size_t size) {
|
| 267 |
+
result.insert(result.end(), data, data + size);
|
| 268 |
+
};
|
| 269 |
+
torch::jit::Pickler pickler(
|
| 270 |
+
writer, nullptr, nullptr, nullptr, nullptr, false);
|
| 271 |
+
pickler.protocol();
|
| 272 |
+
pickler.pushIValue(v);
|
| 273 |
+
pickler.stop();
|
| 274 |
+
}
|
| 275 |
+
return std::string(result.begin(), result.end());
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
inline std::string get_python_cpp_trace() {
|
| 279 |
+
// usage:
|
| 280 |
+
// LOG(INFO) << "stacktrace: "
|
| 281 |
+
// << get_python_cpp_trace();
|
| 282 |
+
// warn: might be slow in getting cpp traces
|
| 283 |
+
// because of slow/broken addr2line
|
| 284 |
+
// in different system libs
|
| 285 |
+
std::shared_ptr<torch::CapturedTraceback> tb =
|
| 286 |
+
torch::CapturedTraceback::gather(
|
| 287 |
+
/*python=*/true, /*script=*/true, /*cpp=*/true);
|
| 288 |
+
torch::SymbolizedTracebacks s_tbs = torch::symbolize({tb.get()});
|
| 289 |
+
const auto& s_tb = s_tbs.tracebacks.at(0);
|
| 290 |
+
constexpr auto TB_FMT_CSTR = FMT_COMPILE("#{} {} from {}:{}\n");
|
| 291 |
+
fmt::memory_buffer buf;
|
| 292 |
+
auto buf_iter = std::back_inserter(buf);
|
| 293 |
+
for (auto idx : c10::irange(s_tb.size())) {
|
| 294 |
+
auto frame_id = s_tb[idx];
|
| 295 |
+
const auto& frame = s_tbs.all_frames.at(frame_id);
|
| 296 |
+
fmt::format_to(
|
| 297 |
+
buf_iter,
|
| 298 |
+
TB_FMT_CSTR,
|
| 299 |
+
idx,
|
| 300 |
+
frame.funcname,
|
| 301 |
+
frame.filename,
|
| 302 |
+
frame.lineno);
|
| 303 |
+
}
|
| 304 |
+
return fmt::to_string(buf);
|
| 305 |
+
}
|
| 306 |
+
|
| 307 |
+
inline c10::Dict<c10::IValue, c10::IValue> new_dict() {
|
| 308 |
+
return c10::Dict<c10::IValue, c10::IValue>(
|
| 309 |
+
c10::AnyType::get(), c10::AnyType::get());
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
inline c10::List<c10::IValue> new_list() {
|
| 313 |
+
return c10::List<c10::IValue>(c10::AnyType::get());
|
| 314 |
+
}
|
| 315 |
+
|
| 316 |
+
inline std::string ranks_str(const std::vector<uint64_t>& ranks) {
|
| 317 |
+
return fmt::format("[{}]", fmt::join(ranks, ", "));
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
} // namespace c10d
|
| 321 |
+
|
| 322 |
+
#else
|
| 323 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 324 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Types.hpp
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <torch/csrc/distributed/c10d/Store.hpp>
|
| 5 |
+
|
| 6 |
+
#include <chrono>
|
| 7 |
+
#include <cstdint>
|
| 8 |
+
|
| 9 |
+
#include <ATen/core/Tensor.h>
|
| 10 |
+
#include <ATen/core/ivalue.h>
|
| 11 |
+
|
| 12 |
+
#include <c10/macros/Macros.h>
|
| 13 |
+
#include <c10/util/intrusive_ptr.h>
|
| 14 |
+
|
| 15 |
+
namespace c10d {
|
| 16 |
+
|
| 17 |
+
// Base class for supplementary data potentially needed by ReduceOps
|
| 18 |
+
struct TORCH_API _SupplementBase : torch::CustomClassHolder {
|
| 19 |
+
~_SupplementBase() override = default;
|
| 20 |
+
};
|
| 21 |
+
|
| 22 |
+
// Supplementary data specific to NCCL PREMUL_SUM
|
| 23 |
+
// The point of use in ProcessGroupNCCL knows how to unpack it.
|
| 24 |
+
struct NCCLPreMulSumSupplement : _SupplementBase {
|
| 25 |
+
double double_factor{0.0};
|
| 26 |
+
at::Tensor tensor_factor;
|
| 27 |
+
NCCLPreMulSumSupplement(double f) : double_factor{f} {}
|
| 28 |
+
NCCLPreMulSumSupplement(at::Tensor t) : tensor_factor{std::move(t)} {
|
| 29 |
+
TORCH_CHECK_EQ(tensor_factor.numel(), 1);
|
| 30 |
+
}
|
| 31 |
+
};
|
| 32 |
+
|
| 33 |
+
// Other ReduceOps that need different supplementary data can also
|
| 34 |
+
// derive from _SupplementBase.
|
| 35 |
+
struct TORCH_API ReduceOp : torch::CustomClassHolder {
|
| 36 |
+
// note(crcrpar): RedOpType could be defined outside of `ReduceOp`
|
| 37 |
+
enum RedOpType : uint8_t {
|
| 38 |
+
SUM = 0,
|
| 39 |
+
AVG = 1,
|
| 40 |
+
PRODUCT = 2,
|
| 41 |
+
MIN = 3,
|
| 42 |
+
MAX = 4,
|
| 43 |
+
BAND = 5, // Bitwise AND
|
| 44 |
+
BOR = 6, // Bitwise OR
|
| 45 |
+
BXOR = 7, // Bitwise XOR
|
| 46 |
+
PREMUL_SUM = 8, // Multiply by a user-supplied constant before summing.
|
| 47 |
+
UNUSED = 9
|
| 48 |
+
};
|
| 49 |
+
|
| 50 |
+
ReduceOp() = default;
|
| 51 |
+
|
| 52 |
+
ReduceOp(RedOpType op) : op_(op) {
|
| 53 |
+
TORCH_INTERNAL_ASSERT(
|
| 54 |
+
op_ != PREMUL_SUM,
|
| 55 |
+
"Use `torch.distributed._make_nccl_premul_sum` to create an instance of ReduceOp with PREMUL_SUM");
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
ReduceOp(
|
| 59 |
+
RedOpType op,
|
| 60 |
+
const c10::intrusive_ptr<_SupplementBase>& optional_supplement) {
|
| 61 |
+
if (optional_supplement) {
|
| 62 |
+
op_ = op;
|
| 63 |
+
} else {
|
| 64 |
+
supplement_ = optional_supplement;
|
| 65 |
+
}
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
// The heap resource supplement_, if it exists, is managed by a
|
| 69 |
+
// c10::intrusive_ptr, so constructors and operator= can be simple
|
| 70 |
+
ReduceOp(const ReduceOp& other) = default;
|
| 71 |
+
ReduceOp& operator=(const ReduceOp& other) = default;
|
| 72 |
+
|
| 73 |
+
ReduceOp(ReduceOp&& other) = default;
|
| 74 |
+
ReduceOp& operator=(ReduceOp&& other) = default;
|
| 75 |
+
~ReduceOp() override = default;
|
| 76 |
+
|
| 77 |
+
operator RedOpType() const {
|
| 78 |
+
return op_;
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
bool operator==(const std::uint8_t other) {
|
| 82 |
+
TORCH_INTERNAL_ASSERT(other < 9, "Invalid other op value");
|
| 83 |
+
return other == op_;
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
bool operator==(const ReduceOp::RedOpType other) {
|
| 87 |
+
return *this == static_cast<std::uint8_t>(other);
|
| 88 |
+
}
|
| 89 |
+
|
| 90 |
+
// todo(crcrpar): Handle `RedOpType::PREMUL_SUM` with its scaling factor.
|
| 91 |
+
bool operator==(const ReduceOp& other) {
|
| 92 |
+
return *this == other.op_;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
RedOpType op_ = SUM;
|
| 96 |
+
// supplement_ is "type-erased" storage for optional supplementary
|
| 97 |
+
// data the op might need.
|
| 98 |
+
// The point of use will know the derived type supplement_ really is,
|
| 99 |
+
// and downcast its pointer to extract the data as the needed type(s).
|
| 100 |
+
// Right now, only PREMUL_SUM needs supplementary data, but the same
|
| 101 |
+
// mechanism could extend to support other nontrivial reduce ops with
|
| 102 |
+
// different supplementary payloads.
|
| 103 |
+
c10::intrusive_ptr<_SupplementBase> supplement_;
|
| 104 |
+
};
|
| 105 |
+
|
| 106 |
+
template <typename T>
|
| 107 |
+
ReduceOp makeNCCLPreMulSum(const T& factor) {
|
| 108 |
+
ReduceOp rop;
|
| 109 |
+
rop.op_ = ReduceOp::PREMUL_SUM;
|
| 110 |
+
rop.supplement_ = c10::make_intrusive<NCCLPreMulSumSupplement>(factor);
|
| 111 |
+
return rop;
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
TORCH_API bool isComplexViewAsRealAllowed(const ReduceOp& reduceOp);
|
| 115 |
+
|
| 116 |
+
constexpr auto kUnsetTimeout = std::chrono::milliseconds(-1);
|
| 117 |
+
|
| 118 |
+
struct BroadcastOptions {
|
| 119 |
+
int64_t rootRank = 0;
|
| 120 |
+
int64_t rootTensor = 0;
|
| 121 |
+
std::chrono::milliseconds timeout = kUnsetTimeout;
|
| 122 |
+
bool asyncOp = true;
|
| 123 |
+
};
|
| 124 |
+
|
| 125 |
+
struct AllreduceOptions {
|
| 126 |
+
ReduceOp reduceOp = ReduceOp::SUM;
|
| 127 |
+
std::chrono::milliseconds timeout = kUnsetTimeout;
|
| 128 |
+
bool asyncOp = true;
|
| 129 |
+
std::optional<at::Tensor> sparseIndices = std::nullopt;
|
| 130 |
+
};
|
| 131 |
+
|
| 132 |
+
struct AllreduceCoalescedOptions : AllreduceOptions {};
|
| 133 |
+
|
| 134 |
+
struct ReduceOptions {
|
| 135 |
+
ReduceOp reduceOp = ReduceOp::SUM;
|
| 136 |
+
int64_t rootRank = 0;
|
| 137 |
+
int64_t rootTensor = 0;
|
| 138 |
+
std::chrono::milliseconds timeout = kUnsetTimeout;
|
| 139 |
+
bool asyncOp = true;
|
| 140 |
+
};
|
| 141 |
+
|
| 142 |
+
struct AllgatherOptions {
|
| 143 |
+
std::chrono::milliseconds timeout = kUnsetTimeout;
|
| 144 |
+
bool asyncOp = true;
|
| 145 |
+
};
|
| 146 |
+
|
| 147 |
+
struct GatherOptions {
|
| 148 |
+
int64_t rootRank = 0;
|
| 149 |
+
std::chrono::milliseconds timeout = kUnsetTimeout;
|
| 150 |
+
bool asyncOp = true;
|
| 151 |
+
};
|
| 152 |
+
|
| 153 |
+
struct ScatterOptions {
|
| 154 |
+
int64_t rootRank = 0;
|
| 155 |
+
std::chrono::milliseconds timeout = kUnsetTimeout;
|
| 156 |
+
bool asyncOp = true;
|
| 157 |
+
};
|
| 158 |
+
|
| 159 |
+
struct ReduceScatterOptions {
|
| 160 |
+
ReduceOp reduceOp = ReduceOp::SUM;
|
| 161 |
+
std::chrono::milliseconds timeout = kUnsetTimeout;
|
| 162 |
+
bool asyncOp = true;
|
| 163 |
+
};
|
| 164 |
+
|
| 165 |
+
struct AllToAllOptions {
|
| 166 |
+
std::chrono::milliseconds timeout = kUnsetTimeout;
|
| 167 |
+
bool asyncOp = true;
|
| 168 |
+
};
|
| 169 |
+
|
| 170 |
+
struct BarrierOptions {
|
| 171 |
+
std::vector<int64_t> device_ids;
|
| 172 |
+
std::chrono::milliseconds timeout = kUnsetTimeout;
|
| 173 |
+
std::optional<at::Device> device;
|
| 174 |
+
bool asyncOp = true;
|
| 175 |
+
};
|
| 176 |
+
|
| 177 |
+
struct DistributedBackendOptions {
|
| 178 |
+
c10::intrusive_ptr<::c10d::Store> store;
|
| 179 |
+
int group_rank;
|
| 180 |
+
int group_size;
|
| 181 |
+
std::chrono::duration<float> timeout;
|
| 182 |
+
std::string group_id;
|
| 183 |
+
std::vector<int64_t> global_ranks_in_group;
|
| 184 |
+
};
|
| 185 |
+
|
| 186 |
+
} // namespace c10d
|
| 187 |
+
|
| 188 |
+
#else
|
| 189 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 190 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/UCCTracing.hpp
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#ifdef USE_C10D_UCC
|
| 5 |
+
|
| 6 |
+
#include <torch/csrc/distributed/c10d/UCCUtils.hpp>
|
| 7 |
+
|
| 8 |
+
namespace c10d {
|
| 9 |
+
|
| 10 |
+
#define RECORD_COMMS_TRACE( \
|
| 11 |
+
_comms_tracer, _work, _opType, _rank, _comm_size, _inTensors, _outTensors) \
|
| 12 |
+
do { \
|
| 13 |
+
if (torch_ucc_config.enable_comms_logger) { \
|
| 14 |
+
_comms_tracer->recordComms( \
|
| 15 |
+
opTypeToString(_opType), \
|
| 16 |
+
(uintptr_t)_work.get(), \
|
| 17 |
+
_rank, \
|
| 18 |
+
_comm_size, \
|
| 19 |
+
_inTensors, \
|
| 20 |
+
_outTensors); \
|
| 21 |
+
} \
|
| 22 |
+
} while (0)
|
| 23 |
+
|
| 24 |
+
// interfaces to collect communication traces
|
| 25 |
+
class TORCH_API CommTraceLogger : public torch::CustomClassHolder {
|
| 26 |
+
private:
|
| 27 |
+
std::vector<std::string> comms_trace_;
|
| 28 |
+
std::vector<std::string> curBlocks_; /* unused */
|
| 29 |
+
std::vector<int64_t> curOutSplitSizes_;
|
| 30 |
+
std::vector<int64_t> curInSplitSizes_;
|
| 31 |
+
int curRoot_ = -1;
|
| 32 |
+
unsigned long seqnum = 0;
|
| 33 |
+
|
| 34 |
+
public:
|
| 35 |
+
void setCurBlock(const std::string& name); /* unused */
|
| 36 |
+
void popBlock(); /* unused */
|
| 37 |
+
// record root info if applicable, e.g., broadcast, gather, scatter
|
| 38 |
+
void recordOptionalInfo(int root = -1);
|
| 39 |
+
// record input/output splits of Alltoallv
|
| 40 |
+
void recordOptionalInfo(
|
| 41 |
+
const std::vector<int64_t>& outputSplitSizes = {},
|
| 42 |
+
const std::vector<int64_t>& inputSplitSizes = {});
|
| 43 |
+
// record essential comms information
|
| 44 |
+
void recordComms(
|
| 45 |
+
const std::string& collName,
|
| 46 |
+
const uintptr_t workReq = 0,
|
| 47 |
+
const int rank = -1,
|
| 48 |
+
const int world_size = -1,
|
| 49 |
+
const std::vector<at::Tensor>& inputTensors = {},
|
| 50 |
+
const std::vector<at::Tensor>& outputTensor = {});
|
| 51 |
+
// return collected comms traces
|
| 52 |
+
std::vector<std::string>& getCommsTrace() {
|
| 53 |
+
return comms_trace_;
|
| 54 |
+
}
|
| 55 |
+
};
|
| 56 |
+
|
| 57 |
+
} // namespace c10d
|
| 58 |
+
|
| 59 |
+
#endif // USE_C10D_UCC
|
| 60 |
+
|
| 61 |
+
#else
|
| 62 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 63 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/UCCUtils.hpp
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#ifdef USE_C10D_UCC
|
| 5 |
+
|
| 6 |
+
#include <torch/csrc/distributed/c10d/ProcessGroup.hpp>
|
| 7 |
+
#include <torch/csrc/distributed/c10d/Store.hpp>
|
| 8 |
+
#include <ucc/api/ucc.h>
|
| 9 |
+
|
| 10 |
+
namespace c10d {
|
| 11 |
+
|
| 12 |
+
// Macro to generate the error message on a non-successful UCC return value.
|
| 13 |
+
#define TORCH_UCC_GET_ERROR_MSG(_err, _error_msg, _result) \
|
| 14 |
+
do { \
|
| 15 |
+
_err = c10::str( \
|
| 16 |
+
"[", \
|
| 17 |
+
std::string(__FILE__), \
|
| 18 |
+
":", \
|
| 19 |
+
std::to_string(__LINE__), \
|
| 20 |
+
"] ", \
|
| 21 |
+
logger->getLogPrefix(), \
|
| 22 |
+
_error_msg, \
|
| 23 |
+
", error code ", \
|
| 24 |
+
_result, \
|
| 25 |
+
": ", \
|
| 26 |
+
ucc_status_string(_result), \
|
| 27 |
+
", system error code ", \
|
| 28 |
+
errno); \
|
| 29 |
+
} while (0)
|
| 30 |
+
|
| 31 |
+
// Macro to throw on a non-successful UCC return value.
|
| 32 |
+
#define TORCH_UCC_CHECK(_cmd, _error_msg) \
|
| 33 |
+
do { \
|
| 34 |
+
ucc_status_t result = _cmd; \
|
| 35 |
+
if (result != UCC_OK) { \
|
| 36 |
+
std::string err; \
|
| 37 |
+
TORCH_UCC_GET_ERROR_MSG(err, _error_msg, result); \
|
| 38 |
+
TORCH_CHECK(false, err); \
|
| 39 |
+
} \
|
| 40 |
+
} while (0)
|
| 41 |
+
|
| 42 |
+
// Macro and throw on a non-successful UCC return value and free its request.
|
| 43 |
+
#define TORCH_UCC_CHECK_REQUEST(_request, _cmd, _error_msg) \
|
| 44 |
+
do { \
|
| 45 |
+
ucc_status_t result = _cmd; \
|
| 46 |
+
if (result != UCC_OK) { \
|
| 47 |
+
std::string err; \
|
| 48 |
+
TORCH_UCC_GET_ERROR_MSG(err, _error_msg, result); \
|
| 49 |
+
if (_request != nullptr) { \
|
| 50 |
+
ucc_collective_finalize(_request); \
|
| 51 |
+
} \
|
| 52 |
+
TORCH_CHECK(false, err); \
|
| 53 |
+
} \
|
| 54 |
+
} while (0)
|
| 55 |
+
|
| 56 |
+
// Macros to print logs with unified format
|
| 57 |
+
#define TORCH_UCC_LOG_ERROR(_phase, _msg) \
|
| 58 |
+
LOG(ERROR) << logger->getLogPrefix(_phase) << "[ERROR] " << _msg;
|
| 59 |
+
#define TORCH_UCC_LOG_INFO(_phase, _msg) \
|
| 60 |
+
LOG(INFO) << logger->getLogPrefix(_phase) << "[INFO] " << _msg;
|
| 61 |
+
#define TORCH_UCC_LOG_DEBUG(_phase, _msg) \
|
| 62 |
+
VLOG(1) << logger->getLogPrefix(_phase) << "[DEBUG] " << _msg;
|
| 63 |
+
|
| 64 |
+
enum torch_ucc_phase_t {
|
| 65 |
+
TORCH_UCC_UNKNOWN = -1,
|
| 66 |
+
TORCH_UCC_INIT,
|
| 67 |
+
TORCH_UCC_HEALTH_CHECK,
|
| 68 |
+
TORCH_UCC_READY,
|
| 69 |
+
TORCH_UCC_COLL_POST,
|
| 70 |
+
TORCH_UCC_COLL_PROGRESS,
|
| 71 |
+
TORCH_UCC_FINALIZE,
|
| 72 |
+
};
|
| 73 |
+
|
| 74 |
+
const std::map<torch_ucc_phase_t, std::string> ucc_phase_map = {
|
| 75 |
+
{TORCH_UCC_UNKNOWN, "UNKNOWN"},
|
| 76 |
+
{TORCH_UCC_INIT, "INIT"},
|
| 77 |
+
{TORCH_UCC_HEALTH_CHECK, "HEALTH_CHECK"},
|
| 78 |
+
{TORCH_UCC_READY, "READY"},
|
| 79 |
+
{TORCH_UCC_COLL_POST, "COLL_POST"},
|
| 80 |
+
{TORCH_UCC_COLL_PROGRESS, "COLL_PROGRESS"},
|
| 81 |
+
{TORCH_UCC_FINALIZE, "FINALIZE"},
|
| 82 |
+
};
|
| 83 |
+
|
| 84 |
+
class CommTraceLogger;
|
| 85 |
+
|
| 86 |
+
class TORCH_API ProcessGroupUCCLogger : public torch::CustomClassHolder {
|
| 87 |
+
public:
|
| 88 |
+
ProcessGroupUCCLogger();
|
| 89 |
+
ProcessGroupUCCLogger(std::string log_prefix, torch_ucc_phase_t phase);
|
| 90 |
+
|
| 91 |
+
std::string getLogPrefix(torch_ucc_phase_t phase = TORCH_UCC_UNKNOWN);
|
| 92 |
+
void setLogPrefix(std::string log_prefix);
|
| 93 |
+
inline void setPhase(torch_ucc_phase_t phase) {
|
| 94 |
+
local_phase = phase;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
void initCommsTracer();
|
| 98 |
+
void flushComms(int rank, int world_size);
|
| 99 |
+
std::shared_ptr<CommTraceLogger> trace_generator = nullptr;
|
| 100 |
+
|
| 101 |
+
protected:
|
| 102 |
+
std::string log_prefix;
|
| 103 |
+
torch_ucc_phase_t local_phase = TORCH_UCC_UNKNOWN;
|
| 104 |
+
bool initialized_CommTraceLogger = false;
|
| 105 |
+
};
|
| 106 |
+
|
| 107 |
+
struct torch_ucc_oob_coll_info_t {
|
| 108 |
+
c10::intrusive_ptr<Store> store;
|
| 109 |
+
uint32_t comm_id;
|
| 110 |
+
int rank;
|
| 111 |
+
int size;
|
| 112 |
+
void* rbuf;
|
| 113 |
+
size_t msglen;
|
| 114 |
+
std::string getKey(std::string key) {
|
| 115 |
+
return std::to_string(comm_id) + key;
|
| 116 |
+
}
|
| 117 |
+
};
|
| 118 |
+
|
| 119 |
+
class CommBase {
|
| 120 |
+
public:
|
| 121 |
+
CommBase(const c10::intrusive_ptr<ProcessGroupUCCLogger>& logger_)
|
| 122 |
+
: logger(logger_) {}
|
| 123 |
+
virtual void progress() = 0;
|
| 124 |
+
virtual void free_request(ucc_coll_req_h request) = 0;
|
| 125 |
+
virtual ~CommBase() {}
|
| 126 |
+
c10::intrusive_ptr<ProcessGroupUCCLogger> logger;
|
| 127 |
+
};
|
| 128 |
+
class CommUCC : public CommBase {
|
| 129 |
+
public:
|
| 130 |
+
ucc_lib_h lib{nullptr};
|
| 131 |
+
ucc_context_h context{nullptr};
|
| 132 |
+
|
| 133 |
+
public:
|
| 134 |
+
void progress() override;
|
| 135 |
+
CommUCC(
|
| 136 |
+
std::shared_ptr<torch_ucc_oob_coll_info_t> oob,
|
| 137 |
+
const c10::intrusive_ptr<ProcessGroupUCCLogger>& logger);
|
| 138 |
+
void free_request(ucc_coll_req_h request) override;
|
| 139 |
+
~CommUCC();
|
| 140 |
+
};
|
| 141 |
+
|
| 142 |
+
ucc_status_t oob_allgather(
|
| 143 |
+
void* sbuf,
|
| 144 |
+
void* rbuf,
|
| 145 |
+
size_t msglen,
|
| 146 |
+
void* coll_info,
|
| 147 |
+
void** req);
|
| 148 |
+
|
| 149 |
+
ucc_status_t oob_allgather_test(void* req);
|
| 150 |
+
|
| 151 |
+
ucc_status_t oob_allgather_free(void* req);
|
| 152 |
+
|
| 153 |
+
// trim: remove spaces before and after the string view
|
| 154 |
+
// implementation borrowed from https://stackoverflow.com/a/17976541
|
| 155 |
+
inline std::string_view trim(std::string_view s) {
|
| 156 |
+
auto wsfront = std::find_if_not(
|
| 157 |
+
s.begin(), s.end(), [](int c) { return std::isspace(c); });
|
| 158 |
+
auto wsback = std::find_if_not(s.rbegin(), s.rend(), [](int c) {
|
| 159 |
+
return std::isspace(c);
|
| 160 |
+
}).base();
|
| 161 |
+
return (
|
| 162 |
+
wsback <= wsfront ? "" : s.substr(wsfront - s.begin(), wsback - wsfront));
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
inline std::string tolower(std::string_view s) {
|
| 166 |
+
std::string result;
|
| 167 |
+
result.reserve(s.size());
|
| 168 |
+
for (auto c : s) {
|
| 169 |
+
result.push_back(std::tolower(c));
|
| 170 |
+
}
|
| 171 |
+
return result;
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
inline std::vector<std::string> parse_list(std::string list) {
|
| 175 |
+
std::vector<std::string> result;
|
| 176 |
+
list = tolower(trim(list));
|
| 177 |
+
while (!list.empty()) {
|
| 178 |
+
const auto end_pos = list.find_first_of(',');
|
| 179 |
+
const auto token = trim(list.substr(0, end_pos));
|
| 180 |
+
result.push_back(std::string(token));
|
| 181 |
+
list = (end_pos != std::string_view::npos) ? list.substr(end_pos + 1) : "";
|
| 182 |
+
}
|
| 183 |
+
return result;
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
} // namespace c10d
|
| 187 |
+
|
| 188 |
+
#endif // USE_C10D_UCC
|
| 189 |
+
|
| 190 |
+
#else
|
| 191 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 192 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/UnixSockUtils.hpp
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <torch/csrc/distributed/c10d/Utils.hpp>
|
| 5 |
+
|
| 6 |
+
namespace c10d::tcputil {
|
| 7 |
+
|
| 8 |
+
#define CONNECT_SOCKET_OFFSET 2
|
| 9 |
+
|
| 10 |
+
inline int poll(struct pollfd* fds, unsigned long nfds, int timeout) {
|
| 11 |
+
return ::poll(fds, nfds, timeout);
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
inline void addPollfd(
|
| 15 |
+
std::vector<struct pollfd>& fds,
|
| 16 |
+
int socket,
|
| 17 |
+
short events) {
|
| 18 |
+
fds.push_back({.fd = socket, .events = events});
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
inline struct ::pollfd getPollfd(int socket, short events) {
|
| 22 |
+
struct ::pollfd res = {.fd = socket, .events = events};
|
| 23 |
+
return res;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
} // namespace c10d::tcputil
|
| 27 |
+
|
| 28 |
+
#else
|
| 29 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 30 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Utils.hpp
ADDED
|
@@ -0,0 +1,750 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <ATen/ATen.h>
|
| 5 |
+
#include <c10/util/Exception.h>
|
| 6 |
+
#include <c10/util/accumulate.h>
|
| 7 |
+
#include <c10/util/env.h>
|
| 8 |
+
#include <c10/util/error.h>
|
| 9 |
+
#include <c10/util/irange.h>
|
| 10 |
+
#include <torch/csrc/distributed/c10d/Types.hpp>
|
| 11 |
+
|
| 12 |
+
#ifdef _WIN32
|
| 13 |
+
#include <winsock2.h>
|
| 14 |
+
#include <ws2tcpip.h>
|
| 15 |
+
typedef SSIZE_T ssize_t;
|
| 16 |
+
#pragma comment(lib, "Ws2_32.lib")
|
| 17 |
+
#else
|
| 18 |
+
#include <fcntl.h>
|
| 19 |
+
#include <netdb.h>
|
| 20 |
+
#include <sys/poll.h>
|
| 21 |
+
#include <sys/socket.h>
|
| 22 |
+
#include <unistd.h>
|
| 23 |
+
#endif
|
| 24 |
+
|
| 25 |
+
#include <sys/types.h>
|
| 26 |
+
|
| 27 |
+
#include <cstdint>
|
| 28 |
+
#include <cstdlib>
|
| 29 |
+
#include <functional>
|
| 30 |
+
#include <string>
|
| 31 |
+
#include <vector>
|
| 32 |
+
|
| 33 |
+
namespace c10d {
|
| 34 |
+
|
| 35 |
+
TORCH_API size_t getTensorsNumel(const std::vector<at::Tensor>& tensors);
|
| 36 |
+
|
| 37 |
+
// Retrieve tensor shapes from a given tensor.
|
| 38 |
+
TORCH_API std::vector<at::Tensor> getTensorShapes(
|
| 39 |
+
const std::vector<at::Tensor>& tensors);
|
| 40 |
+
|
| 41 |
+
// Use -2 to represent unset state of env vars
|
| 42 |
+
#define C10D_ENV_NOT_SET -2
|
| 43 |
+
|
| 44 |
+
#define WARN_ENV_VAR_ONCE(deprecated_env, new_env) \
|
| 45 |
+
TORCH_WARN_ONCE( \
|
| 46 |
+
"Environment variable " + deprecated_env + " is deprecated; use " + \
|
| 47 |
+
new_env + " instead");
|
| 48 |
+
|
| 49 |
+
// Turns at::IntArrayRef into "(1, 2, 3, 4)".
|
| 50 |
+
inline std::string toString(at::IntArrayRef l) {
|
| 51 |
+
std::stringstream ss;
|
| 52 |
+
ss << '(';
|
| 53 |
+
for (const auto i : c10::irange(l.size())) {
|
| 54 |
+
if (i > 0) {
|
| 55 |
+
ss << ", ";
|
| 56 |
+
}
|
| 57 |
+
ss << l[i];
|
| 58 |
+
}
|
| 59 |
+
ss << ')';
|
| 60 |
+
return ss.str();
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
inline std::string toString(const c10::Layout& layout) {
|
| 64 |
+
std::stringstream ss;
|
| 65 |
+
ss << layout;
|
| 66 |
+
return ss.str();
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
inline void assertSameType(
|
| 70 |
+
const at::DeprecatedTypeProperties& type,
|
| 71 |
+
const std::vector<at::Tensor>& tensors) {
|
| 72 |
+
for (const auto i : c10::irange(tensors.size())) {
|
| 73 |
+
if (!tensors[i].options().type_equal(type.options())) {
|
| 74 |
+
const std::string expected = type.toString();
|
| 75 |
+
const std::string actual = tensors[i].toString();
|
| 76 |
+
throw std::invalid_argument(
|
| 77 |
+
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
|
| 78 |
+
"mixed types (" + expected + " and " + actual + ")");
|
| 79 |
+
}
|
| 80 |
+
}
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
inline std::vector<std::string> split(
|
| 84 |
+
char separator,
|
| 85 |
+
const std::string& string) {
|
| 86 |
+
std::vector<std::string> pieces;
|
| 87 |
+
std::stringstream ss(string);
|
| 88 |
+
std::string item;
|
| 89 |
+
while (std::getline(ss, item, separator)) {
|
| 90 |
+
pieces.push_back(std::move(item));
|
| 91 |
+
}
|
| 92 |
+
return pieces;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
inline std::string getCvarString(
|
| 96 |
+
const std::vector<std::string>& env,
|
| 97 |
+
const char* def) {
|
| 98 |
+
std::string ret(def);
|
| 99 |
+
|
| 100 |
+
if (env.empty()) {
|
| 101 |
+
TORCH_CHECK(false, "No environment variables passed");
|
| 102 |
+
return ret;
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
/* parse environment variable in reverse order, so the early
|
| 106 |
+
* versions of a variable get higher priority than the latter
|
| 107 |
+
* versions of the same variable */
|
| 108 |
+
for (ssize_t i = static_cast<ssize_t>(env.size()) - 1; i >= 0; i--) {
|
| 109 |
+
auto val = c10::utils::get_env(env[i].c_str());
|
| 110 |
+
if (!val.has_value()) {
|
| 111 |
+
continue;
|
| 112 |
+
} else if (i) {
|
| 113 |
+
WARN_ENV_VAR_ONCE(env[i], env[0]);
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
ret = val.value();
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
return ret;
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
inline int getCvarInt(const std::vector<std::string>& env, int def) {
|
| 123 |
+
int ret = def;
|
| 124 |
+
|
| 125 |
+
if (env.empty()) {
|
| 126 |
+
TORCH_CHECK(false, "No environment variables passed");
|
| 127 |
+
return ret;
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
/* parse environment variable in reverse order, so the early
|
| 131 |
+
* versions of a variable get higher priority than the latter
|
| 132 |
+
* versions of the same variable */
|
| 133 |
+
for (ssize_t i = static_cast<ssize_t>(env.size()) - 1; i >= 0; i--) {
|
| 134 |
+
const auto val = c10::utils::get_env(env[i].c_str());
|
| 135 |
+
if (!val.has_value()) {
|
| 136 |
+
continue;
|
| 137 |
+
} else if (i) {
|
| 138 |
+
WARN_ENV_VAR_ONCE(env[i], env[0]);
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
try {
|
| 142 |
+
ret = std::stoi(val.value());
|
| 143 |
+
} catch (std::exception&) {
|
| 144 |
+
TORCH_CHECK(false, "Invalid value for environment variable: " + env[i]);
|
| 145 |
+
}
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
return ret;
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
inline bool getCvarBool(const std::vector<std::string>& env, bool def) {
|
| 152 |
+
bool ret = def;
|
| 153 |
+
|
| 154 |
+
if (env.empty()) {
|
| 155 |
+
TORCH_CHECK(false, "No environment variables passed");
|
| 156 |
+
return ret;
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
/* parse environment variable in reverse order, so the early
|
| 160 |
+
* versions of a variable get higher priority than the latter
|
| 161 |
+
* versions of the same variable */
|
| 162 |
+
for (ssize_t i = static_cast<ssize_t>(env.size()) - 1; i >= 0; i--) {
|
| 163 |
+
auto val = c10::utils::get_env(env[i].c_str());
|
| 164 |
+
if (!val.has_value()) {
|
| 165 |
+
continue;
|
| 166 |
+
} else if (i) {
|
| 167 |
+
WARN_ENV_VAR_ONCE(env[i], env[0]);
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
for (auto& x : val.value()) {
|
| 171 |
+
// NOLINTNEXTLINE(*-narrowing-conversions)
|
| 172 |
+
x = std::tolower(x);
|
| 173 |
+
}
|
| 174 |
+
|
| 175 |
+
if (val == "y" || val == "yes" || val == "1" || val == "t" ||
|
| 176 |
+
val == "true") {
|
| 177 |
+
ret = true;
|
| 178 |
+
} else if (
|
| 179 |
+
val == "n" || val == "no" || val == "0" || val == "f" ||
|
| 180 |
+
val == "false") {
|
| 181 |
+
ret = false;
|
| 182 |
+
} else {
|
| 183 |
+
TORCH_CHECK(false, "Invalid value for environment variable: " + env[i]);
|
| 184 |
+
return ret;
|
| 185 |
+
}
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
return ret;
|
| 189 |
+
}
|
| 190 |
+
|
| 191 |
+
inline void assertSameSizes(
|
| 192 |
+
const at::IntArrayRef& sizes,
|
| 193 |
+
const std::vector<at::Tensor>& tensors) {
|
| 194 |
+
for (const auto i : c10::irange(tensors.size())) {
|
| 195 |
+
if (!tensors[i].sizes().equals(sizes)) {
|
| 196 |
+
const auto expected = toString(sizes);
|
| 197 |
+
const auto actual = toString(tensors[i].sizes());
|
| 198 |
+
throw std::invalid_argument(
|
| 199 |
+
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
|
| 200 |
+
"mixed sizes (" + expected + " and " + actual + ")");
|
| 201 |
+
}
|
| 202 |
+
}
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
inline void assertSameSizeAndType(const std::vector<at::Tensor>& tensors) {
|
| 206 |
+
// Ensure we have at least one tensor
|
| 207 |
+
if (tensors.empty()) {
|
| 208 |
+
throw std::invalid_argument("argument is empty");
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
// Ensure all tensors have identical type and shape
|
| 212 |
+
auto options = tensors[0].options();
|
| 213 |
+
auto sizes = tensors[0].sizes();
|
| 214 |
+
for (const auto i : c10::irange(1, tensors.size())) {
|
| 215 |
+
if (!tensors[i].options().type_equal(options)) {
|
| 216 |
+
const auto expected = toString(options);
|
| 217 |
+
const auto actual = toString(tensors[i].options());
|
| 218 |
+
throw std::invalid_argument(
|
| 219 |
+
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
|
| 220 |
+
"argument contains mixed types (" + expected + " and " + actual +
|
| 221 |
+
")");
|
| 222 |
+
}
|
| 223 |
+
if (!tensors[i].sizes().equals(sizes)) {
|
| 224 |
+
const auto expected = toString(sizes);
|
| 225 |
+
const auto actual = toString(tensors[i].sizes());
|
| 226 |
+
throw std::invalid_argument(
|
| 227 |
+
// NOLINTNEXTLINE(performance-inefficient-string-concatenation)
|
| 228 |
+
"argument contains mixed types (" + expected + " and " + actual +
|
| 229 |
+
")");
|
| 230 |
+
}
|
| 231 |
+
}
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
inline void assertTypeMatch(
|
| 235 |
+
const std::function<void(const std::string&)>& fn,
|
| 236 |
+
const at::DeprecatedTypeProperties& type,
|
| 237 |
+
const at::ArrayRef<at::Tensor> tensors,
|
| 238 |
+
size_t index) {
|
| 239 |
+
if (!tensors[index].options().type_equal(type.options())) {
|
| 240 |
+
fn("invalid tensor type at index " + std::to_string(index) + " (expected " +
|
| 241 |
+
type.toString() + ", got " + tensors[index].toString() + ")");
|
| 242 |
+
}
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
inline void assertTypeMatch(
|
| 246 |
+
const std::function<void(const std::string&)>& fn,
|
| 247 |
+
const at::TensorOptions& options,
|
| 248 |
+
const at::ArrayRef<at::Tensor> tensors,
|
| 249 |
+
size_t index) {
|
| 250 |
+
if (!tensors[index].options().type_equal(options)) {
|
| 251 |
+
fn("invalid tensor type at index " + std::to_string(index) + " (expected " +
|
| 252 |
+
toString(options) + ", got " + toString(tensors[index].options()) + ")");
|
| 253 |
+
}
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
inline void assertSizesMatch(
|
| 257 |
+
const std::function<void(const std::string&)>& fn,
|
| 258 |
+
const at::IntArrayRef& sizes,
|
| 259 |
+
const at::ArrayRef<at::Tensor> tensors,
|
| 260 |
+
size_t index) {
|
| 261 |
+
if (tensors[index].sizes() != sizes) {
|
| 262 |
+
fn("invalid tensor size at index " + std::to_string(index) + " (expected " +
|
| 263 |
+
toString(sizes) + ", got " + toString(tensors[index].sizes()) + ")");
|
| 264 |
+
}
|
| 265 |
+
}
|
| 266 |
+
|
| 267 |
+
inline void assertLayoutMatch(
|
| 268 |
+
const std::function<void(const std::string&)>& fn,
|
| 269 |
+
const c10::Layout& expected,
|
| 270 |
+
const at::ArrayRef<at::Tensor> tensors,
|
| 271 |
+
size_t index) {
|
| 272 |
+
const auto& actual = tensors[index].layout();
|
| 273 |
+
if (actual != expected) {
|
| 274 |
+
fn("invalid tensor layout at index " + std::to_string(index) +
|
| 275 |
+
" (expected " + toString(expected) + ", got " + toString(actual) + ")");
|
| 276 |
+
}
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
inline void assertLayoutMatch(
|
| 280 |
+
const std::function<void(const std::string&)>& fn,
|
| 281 |
+
const at::ArrayRef<at::Tensor> tensors) {
|
| 282 |
+
const auto& layout = tensors[0].layout();
|
| 283 |
+
for (const auto i : c10::irange(1, tensors.size())) {
|
| 284 |
+
assertLayoutMatch(fn, layout, tensors, i);
|
| 285 |
+
}
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
inline void assertNonEmpty(
|
| 289 |
+
const std::function<void(const std::string&)>& fn,
|
| 290 |
+
const at::ArrayRef<at::Tensor> tensors) {
|
| 291 |
+
if (tensors.empty()) {
|
| 292 |
+
fn("requires non-empty tensor list");
|
| 293 |
+
}
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
inline void assertSingleElement(
|
| 297 |
+
const std::function<void(const std::string&)>& fn,
|
| 298 |
+
const at::ArrayRef<at::Tensor> tensors) {
|
| 299 |
+
if (tensors.size() != 1) {
|
| 300 |
+
fn("requires a single-element tensor list");
|
| 301 |
+
}
|
| 302 |
+
}
|
| 303 |
+
|
| 304 |
+
inline void assertSingleElementInput(
|
| 305 |
+
const std::function<void(const std::string&)>& fn,
|
| 306 |
+
const at::ArrayRef<at::Tensor> tensors) {
|
| 307 |
+
if (tensors.size() != 1) {
|
| 308 |
+
fn("requires a single-element input tensor list");
|
| 309 |
+
}
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
inline void assertSingleElementOutput(
|
| 313 |
+
const std::function<void(const std::string&)>& fn,
|
| 314 |
+
const at::ArrayRef<at::Tensor> tensors) {
|
| 315 |
+
if (tensors.size() != 1) {
|
| 316 |
+
fn("requires a single-element output tensor list");
|
| 317 |
+
}
|
| 318 |
+
}
|
| 319 |
+
|
| 320 |
+
inline void assertRootRank(
|
| 321 |
+
const std::function<void(const std::string&)>& fn,
|
| 322 |
+
int64_t rank,
|
| 323 |
+
int64_t size) {
|
| 324 |
+
if (rank < 0 || rank >= size) {
|
| 325 |
+
fn("invalid root rank: " + std::to_string(rank));
|
| 326 |
+
}
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
inline void assertRootTensor(
|
| 330 |
+
const std::function<void(const std::string&)>& fn,
|
| 331 |
+
int64_t rank,
|
| 332 |
+
int64_t size) {
|
| 333 |
+
if (rank < 0 || rank >= size) {
|
| 334 |
+
fn("invalid root tensor: " + std::to_string(rank));
|
| 335 |
+
}
|
| 336 |
+
}
|
| 337 |
+
|
| 338 |
+
inline void assertDense(
|
| 339 |
+
const std::function<void(const std::string&)>& fn,
|
| 340 |
+
const at::ArrayRef<at::Tensor> tensors) {
|
| 341 |
+
const auto& layout = tensors[0].layout();
|
| 342 |
+
if (layout != at::kStrided) {
|
| 343 |
+
fn("only supports dense tensors");
|
| 344 |
+
}
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
inline void assertCPU(
|
| 348 |
+
const std::function<void(const std::string&)>& fn,
|
| 349 |
+
const at::ArrayRef<at::Tensor> tensors) {
|
| 350 |
+
const auto& device = tensors[0].device();
|
| 351 |
+
if (device.type() != at::kCPU) {
|
| 352 |
+
fn("only supports CPU tensors");
|
| 353 |
+
}
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
inline void assertSameDevice(
|
| 357 |
+
const std::function<void(const std::string&)>& fn,
|
| 358 |
+
const at::ArrayRef<at::Tensor> tensors) {
|
| 359 |
+
if (tensors.size() < 2) {
|
| 360 |
+
return;
|
| 361 |
+
}
|
| 362 |
+
const auto& device = tensors[0].device();
|
| 363 |
+
for (const auto i : c10::irange(1, tensors.size())) {
|
| 364 |
+
if (tensors[i].device() != device) {
|
| 365 |
+
fn("tensors should be on the same device");
|
| 366 |
+
}
|
| 367 |
+
}
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
inline void assertTypeAndSizesMatch(
|
| 371 |
+
const std::function<void(const std::string&)>& fn,
|
| 372 |
+
const at::ArrayRef<at::Tensor> tensors,
|
| 373 |
+
const at::DeprecatedTypeProperties& type,
|
| 374 |
+
const at::IntArrayRef& sizes) {
|
| 375 |
+
for (const auto i : c10::irange(tensors.size())) {
|
| 376 |
+
assertTypeMatch(fn, type, tensors, i);
|
| 377 |
+
assertSizesMatch(fn, sizes, tensors, i);
|
| 378 |
+
}
|
| 379 |
+
}
|
| 380 |
+
|
| 381 |
+
inline void assertTypeAndSizesMatch(
|
| 382 |
+
const std::function<void(const std::string&)>& fn,
|
| 383 |
+
const at::ArrayRef<at::Tensor> tensors,
|
| 384 |
+
const at::TensorOptions& options,
|
| 385 |
+
const at::IntArrayRef& sizes) {
|
| 386 |
+
for (const auto i : c10::irange(tensors.size())) {
|
| 387 |
+
assertTypeMatch(fn, options, tensors, i);
|
| 388 |
+
assertSizesMatch(fn, sizes, tensors, i);
|
| 389 |
+
}
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
inline void assertTypeAndSizesMatch(
|
| 393 |
+
const std::function<void(const std::string&)>& fn,
|
| 394 |
+
const at::ArrayRef<at::Tensor> tensors) {
|
| 395 |
+
const auto& options = tensors[0].options();
|
| 396 |
+
const auto sizes = tensors[0].sizes();
|
| 397 |
+
assertTypeAndSizesMatch(fn, tensors.slice(1), options, sizes);
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
// Copied from ATen/core/functional.h.
|
| 401 |
+
template <typename F, typename T>
|
| 402 |
+
inline auto fmap(T& inputs, const F& fn)
|
| 403 |
+
-> std::vector<decltype(fn(*inputs.begin()))> {
|
| 404 |
+
std::vector<decltype(fn(*inputs.begin()))> r;
|
| 405 |
+
r.reserve(inputs.size());
|
| 406 |
+
for (auto& input : inputs) {
|
| 407 |
+
r.push_back(fn(input));
|
| 408 |
+
}
|
| 409 |
+
return r;
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
// Copied from torch/csrc/utils/tensor_flatten.h.
|
| 413 |
+
inline at::Tensor flattenDenseTensors(at::TensorList tensors) {
|
| 414 |
+
static const auto flatten = [](const at::Tensor& t) {
|
| 415 |
+
return t.contiguous().view({-1});
|
| 416 |
+
};
|
| 417 |
+
if (tensors.size() == 1) {
|
| 418 |
+
return flatten(tensors[0]);
|
| 419 |
+
}
|
| 420 |
+
return at::cat(::c10d::fmap(tensors, flatten));
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
+
inline at::Tensor newLikeFlat(
|
| 424 |
+
std::vector<std::vector<at::Tensor>>& tensors,
|
| 425 |
+
size_t deviceIdx) {
|
| 426 |
+
if (tensors.empty() || tensors[0].empty()) {
|
| 427 |
+
TORCH_CHECK(false, "Received an empty list");
|
| 428 |
+
}
|
| 429 |
+
if (deviceIdx >= tensors.size()) {
|
| 430 |
+
TORCH_CHECK(false, "Invalid device index");
|
| 431 |
+
}
|
| 432 |
+
auto& t = tensors[deviceIdx][0];
|
| 433 |
+
auto device = t.device();
|
| 434 |
+
for (const auto i : c10::irange(1, tensors[deviceIdx].size())) {
|
| 435 |
+
if (tensors[deviceIdx][i].device() != device) {
|
| 436 |
+
TORCH_CHECK(false, "Expecting all tensors on the same device");
|
| 437 |
+
}
|
| 438 |
+
}
|
| 439 |
+
at::DeviceGuard gpuGuard(device);
|
| 440 |
+
std::vector<int64_t> sizes{static_cast<int64_t>(tensors[deviceIdx].size())};
|
| 441 |
+
std::vector<int64_t> strides{t.numel()};
|
| 442 |
+
sizes.insert(sizes.end(), t.sizes().begin(), t.sizes().end());
|
| 443 |
+
strides.insert(strides.end(), t.strides().begin(), t.strides().end());
|
| 444 |
+
return at::empty_strided(
|
| 445 |
+
sizes, strides, t.options().memory_format(std::nullopt));
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
inline at::Tensor newLikeFlat(std::vector<at::Tensor>& tensors) {
|
| 449 |
+
if (tensors.empty()) {
|
| 450 |
+
TORCH_CHECK(false, "Received an empty list");
|
| 451 |
+
}
|
| 452 |
+
auto& t = tensors[0];
|
| 453 |
+
at::DeviceGuard gpuGuard(t.device());
|
| 454 |
+
std::vector<int64_t> sizes{static_cast<int64_t>(tensors.size())};
|
| 455 |
+
sizes.insert(sizes.end(), t.sizes().begin(), t.sizes().end());
|
| 456 |
+
return at::empty(sizes, t.options());
|
| 457 |
+
}
|
| 458 |
+
|
| 459 |
+
inline std::vector<std::vector<int64_t>> getSizes(
|
| 460 |
+
const std::vector<at::Tensor>& tensors) {
|
| 461 |
+
std::vector<std::vector<int64_t>> sizes(tensors.size());
|
| 462 |
+
for (const auto i : c10::irange(tensors.size())) {
|
| 463 |
+
sizes[i] = tensors[i].sizes().vec();
|
| 464 |
+
}
|
| 465 |
+
return sizes;
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
inline std::vector<int> getDevices(const std::vector<at::Tensor>& tensors) {
|
| 469 |
+
std::vector<int> devices(tensors.size(), -1);
|
| 470 |
+
if (tensors[0].device().is_cuda()) {
|
| 471 |
+
for (const auto i : c10::irange(tensors.size())) {
|
| 472 |
+
// NOLINTNEXTLINE(bugprone-signed-char-misuse)
|
| 473 |
+
devices[i] = tensors[i].storage().device().index();
|
| 474 |
+
}
|
| 475 |
+
}
|
| 476 |
+
return devices;
|
| 477 |
+
}
|
| 478 |
+
|
| 479 |
+
template <typename T>
|
| 480 |
+
inline T* getDataPointer(const at::Tensor& tensor) {
|
| 481 |
+
// This method is only used in ProcessGroupGloo for now. Call sites must make
|
| 482 |
+
// sure that the input tensor is contiguous. It is OK if the tensor does not
|
| 483 |
+
// start from the beginning of the storage. For example, it could come from
|
| 484 |
+
// chunk(..., dim=0)[1]. Hence, we need to use data_ptr() instead of
|
| 485 |
+
// tensor.storage().data()
|
| 486 |
+
// NB: not using tensor.data<T>() because tensor is not aware of gloo::TYPE
|
| 487 |
+
return static_cast<T*>(tensor.data_ptr());
|
| 488 |
+
}
|
| 489 |
+
|
| 490 |
+
template <typename T>
|
| 491 |
+
std::vector<T*> getDataPointers(const std::vector<at::Tensor>& tensors) {
|
| 492 |
+
std::vector<T*> ptrs(tensors.size());
|
| 493 |
+
for (const auto i : c10::irange(tensors.size())) {
|
| 494 |
+
ptrs[i] = getDataPointer<T>(tensors[i]);
|
| 495 |
+
}
|
| 496 |
+
return ptrs;
|
| 497 |
+
}
|
| 498 |
+
|
| 499 |
+
// For alltoall split size sanity check
|
| 500 |
+
inline void checkSplitSizes(
|
| 501 |
+
const std::vector<int64_t>& split_sizes,
|
| 502 |
+
const at::Tensor& tensor,
|
| 503 |
+
int group_size) {
|
| 504 |
+
if (split_sizes.empty()) {
|
| 505 |
+
TORCH_CHECK(
|
| 506 |
+
tensor.size(0) % group_size == 0,
|
| 507 |
+
"Tensor's dim 0 does not divide equally across group size");
|
| 508 |
+
} else {
|
| 509 |
+
TORCH_CHECK(
|
| 510 |
+
split_sizes.size() == static_cast<size_t>(group_size),
|
| 511 |
+
"Number of tensor splits not equal to group size");
|
| 512 |
+
const auto sum = c10::sum_integers(split_sizes);
|
| 513 |
+
TORCH_CHECK(
|
| 514 |
+
sum == tensor.size(0), "Split sizes doesn't match total dim 0 size");
|
| 515 |
+
}
|
| 516 |
+
}
|
| 517 |
+
|
| 518 |
+
// Compute alltoall lengths and offsets, handling multi-dimension tensors
|
| 519 |
+
template <typename T>
|
| 520 |
+
size_t computeLengthsAndOffsets(
|
| 521 |
+
const std::vector<int64_t>& split_sizes,
|
| 522 |
+
const at::Tensor& tensor,
|
| 523 |
+
std::vector<T>* lengths,
|
| 524 |
+
std::vector<T>* offsets) {
|
| 525 |
+
size_t group_size = lengths->size();
|
| 526 |
+
bool equal_splits = false;
|
| 527 |
+
size_t dim0_size = tensor.size(0);
|
| 528 |
+
size_t row_size = (dim0_size ? tensor.numel() / dim0_size : 1);
|
| 529 |
+
size_t split_size = 0;
|
| 530 |
+
size_t offset = 0;
|
| 531 |
+
|
| 532 |
+
if (split_sizes.empty()) {
|
| 533 |
+
equal_splits = true;
|
| 534 |
+
split_size = tensor.size(0) / group_size;
|
| 535 |
+
}
|
| 536 |
+
for (const auto i : c10::irange(group_size)) {
|
| 537 |
+
size_t length = row_size * (equal_splits ? split_size : split_sizes[i]);
|
| 538 |
+
(*lengths)[i] = length;
|
| 539 |
+
(*offsets)[i] = offset;
|
| 540 |
+
// TODO: see if we should add overflow protection for offset
|
| 541 |
+
offset += length;
|
| 542 |
+
}
|
| 543 |
+
return offset;
|
| 544 |
+
}
|
| 545 |
+
|
| 546 |
+
template <typename T>
|
| 547 |
+
size_t computeLengthsAndOffsets(
|
| 548 |
+
const std::vector<at::Tensor>& tensors,
|
| 549 |
+
std::vector<T>* lengths,
|
| 550 |
+
std::vector<T>* offsets) {
|
| 551 |
+
size_t group_size = lengths->size();
|
| 552 |
+
size_t offset = 0;
|
| 553 |
+
for (const auto i : c10::irange(group_size)) {
|
| 554 |
+
size_t length = tensors[i].numel();
|
| 555 |
+
(*lengths)[i] = length;
|
| 556 |
+
(*offsets)[i] = offset;
|
| 557 |
+
offset += length;
|
| 558 |
+
}
|
| 559 |
+
return offset;
|
| 560 |
+
}
|
| 561 |
+
|
| 562 |
+
// Get the start and stride of the global rank from a list of global ranks
|
| 563 |
+
// If the global ranks do not follow the consecutive rule, the stride will be -1
|
| 564 |
+
void TORCH_API getGlobalRankStartAndStride(
|
| 565 |
+
const std::vector<uint64_t>& globalRanksInGroup,
|
| 566 |
+
int& globalRankStart,
|
| 567 |
+
int& globalRankStride);
|
| 568 |
+
|
| 569 |
+
using RankType = uint32_t;
|
| 570 |
+
using SizeType = uint64_t;
|
| 571 |
+
|
| 572 |
+
// `errno` is only meaningful when it fails. E.g., a successful `fork()` sets
|
| 573 |
+
// `errno` to `EINVAL` in child process on some macos
|
| 574 |
+
// (https://stackoverflow.com/a/20295079), and thus `errno` should really only
|
| 575 |
+
// be inspected if an error occurred.
|
| 576 |
+
//
|
| 577 |
+
// `success_cond` is an expression used to check if an error has happened. So
|
| 578 |
+
// for `fork()`, we can use `SYSCHECK(pid = fork(), pid != -1)`. The function
|
| 579 |
+
// output is stored in variable `__output` and may be used in `success_cond`.
|
| 580 |
+
#ifdef _WIN32
|
| 581 |
+
#define SYSCHECK(expr, success_cond) \
|
| 582 |
+
while (true) { \
|
| 583 |
+
auto __output = (expr); \
|
| 584 |
+
auto errno_local = WSAGetLastError(); \
|
| 585 |
+
(void)__output; \
|
| 586 |
+
if (!(success_cond)) { \
|
| 587 |
+
if (errno == EINTR) { \
|
| 588 |
+
continue; \
|
| 589 |
+
} else if ( \
|
| 590 |
+
errno_local == WSAETIMEDOUT || errno_local == WSAEWOULDBLOCK) { \
|
| 591 |
+
C10_THROW_ERROR(DistNetworkError, "Socket Timeout"); \
|
| 592 |
+
} else { \
|
| 593 |
+
C10_THROW_ERROR(DistNetworkError, c10::utils::str_error(errno_local)); \
|
| 594 |
+
} \
|
| 595 |
+
} else { \
|
| 596 |
+
break; \
|
| 597 |
+
} \
|
| 598 |
+
}
|
| 599 |
+
#else
|
| 600 |
+
#define SYSCHECK(expr, success_cond) \
|
| 601 |
+
while (true) { \
|
| 602 |
+
auto __output = (expr); \
|
| 603 |
+
(void)__output; \
|
| 604 |
+
if (!(success_cond)) { \
|
| 605 |
+
if (errno == EINTR) { \
|
| 606 |
+
continue; \
|
| 607 |
+
} else if (errno == EAGAIN || errno == EWOULDBLOCK) { \
|
| 608 |
+
C10_THROW_ERROR(DistNetworkError, "Socket Timeout"); \
|
| 609 |
+
} else { \
|
| 610 |
+
C10_THROW_ERROR(DistNetworkError, c10::utils::str_error(errno)); \
|
| 611 |
+
} \
|
| 612 |
+
} else { \
|
| 613 |
+
break; \
|
| 614 |
+
} \
|
| 615 |
+
}
|
| 616 |
+
#endif
|
| 617 |
+
|
| 618 |
+
// Most functions indicate error by returning `-1`. This is a helper macro for
|
| 619 |
+
// this common case with `SYSCHECK`.
|
| 620 |
+
// Since SOCKET_ERROR = -1 in MSVC, so also leverage SYSCHECK_ERR_RETURN_NEG1
|
| 621 |
+
#define SYSCHECK_ERR_RETURN_NEG1(expr) SYSCHECK(expr, __output != -1)
|
| 622 |
+
|
| 623 |
+
namespace tcputil {
|
| 624 |
+
|
| 625 |
+
// Send and receive
|
| 626 |
+
template <typename T>
|
| 627 |
+
void sendBytes(
|
| 628 |
+
int socket,
|
| 629 |
+
const T* buffer,
|
| 630 |
+
size_t length,
|
| 631 |
+
bool moreData = false) {
|
| 632 |
+
size_t bytesToSend = sizeof(T) * length;
|
| 633 |
+
if (bytesToSend == 0) {
|
| 634 |
+
return;
|
| 635 |
+
}
|
| 636 |
+
|
| 637 |
+
auto currentBytes = reinterpret_cast<const char*>(buffer);
|
| 638 |
+
|
| 639 |
+
int flags = 0;
|
| 640 |
+
|
| 641 |
+
#ifdef MSG_MORE
|
| 642 |
+
if (moreData) { // there is more data to send
|
| 643 |
+
flags |= MSG_MORE;
|
| 644 |
+
}
|
| 645 |
+
#endif
|
| 646 |
+
|
| 647 |
+
// Ignore SIGPIPE as the send() return value is always checked for error
|
| 648 |
+
#ifdef MSG_NOSIGNAL
|
| 649 |
+
flags |= MSG_NOSIGNAL;
|
| 650 |
+
#endif
|
| 651 |
+
|
| 652 |
+
while (bytesToSend > 0) {
|
| 653 |
+
ssize_t bytesSent = 0;
|
| 654 |
+
SYSCHECK_ERR_RETURN_NEG1(
|
| 655 |
+
bytesSent = ::send(socket, currentBytes, bytesToSend, flags))
|
| 656 |
+
if (bytesSent == 0) {
|
| 657 |
+
C10_THROW_ERROR(
|
| 658 |
+
DistNetworkError,
|
| 659 |
+
"Failed to send, sent 0 bytes. "
|
| 660 |
+
"Connection was likely closed. "
|
| 661 |
+
"Did the remote server shutdown or crash?");
|
| 662 |
+
}
|
| 663 |
+
|
| 664 |
+
bytesToSend -= bytesSent;
|
| 665 |
+
currentBytes += bytesSent;
|
| 666 |
+
}
|
| 667 |
+
}
|
| 668 |
+
|
| 669 |
+
template <typename T>
|
| 670 |
+
void recvBytes(int socket, T* buffer, size_t length) {
|
| 671 |
+
size_t bytesToReceive = sizeof(T) * length;
|
| 672 |
+
if (bytesToReceive == 0) {
|
| 673 |
+
return;
|
| 674 |
+
}
|
| 675 |
+
|
| 676 |
+
auto currentBytes = reinterpret_cast<char*>(buffer);
|
| 677 |
+
|
| 678 |
+
while (bytesToReceive > 0) {
|
| 679 |
+
ssize_t bytesReceived = 0;
|
| 680 |
+
SYSCHECK_ERR_RETURN_NEG1(
|
| 681 |
+
bytesReceived = recv(socket, currentBytes, bytesToReceive, 0))
|
| 682 |
+
if (bytesReceived == 0) {
|
| 683 |
+
C10_THROW_ERROR(
|
| 684 |
+
DistNetworkError,
|
| 685 |
+
"Failed to recv, got 0 bytes. "
|
| 686 |
+
"Connection was likely closed. "
|
| 687 |
+
"Did the remote server shutdown or crash?");
|
| 688 |
+
}
|
| 689 |
+
|
| 690 |
+
bytesToReceive -= bytesReceived;
|
| 691 |
+
currentBytes += bytesReceived;
|
| 692 |
+
}
|
| 693 |
+
}
|
| 694 |
+
|
| 695 |
+
// send a vector's length and data
|
| 696 |
+
template <typename T>
|
| 697 |
+
void sendVector(int socket, const std::vector<T>& vec, bool moreData = false) {
|
| 698 |
+
SizeType size = vec.size();
|
| 699 |
+
sendBytes<SizeType>(socket, &size, 1, true);
|
| 700 |
+
sendBytes<T>(socket, vec.data(), size, moreData);
|
| 701 |
+
}
|
| 702 |
+
|
| 703 |
+
// receive a vector as sent in sendVector
|
| 704 |
+
template <typename T>
|
| 705 |
+
std::vector<T> recvVector(int socket) {
|
| 706 |
+
SizeType valueSize = 0;
|
| 707 |
+
recvBytes<SizeType>(socket, &valueSize, 1);
|
| 708 |
+
std::vector<T> value(valueSize);
|
| 709 |
+
recvBytes<T>(socket, value.data(), value.size());
|
| 710 |
+
return value;
|
| 711 |
+
}
|
| 712 |
+
|
| 713 |
+
// this is only for convenience when sending rvalues
|
| 714 |
+
template <typename T>
|
| 715 |
+
void sendValue(int socket, const T& value, bool moreData = false) {
|
| 716 |
+
sendBytes<T>(socket, &value, 1, moreData);
|
| 717 |
+
}
|
| 718 |
+
|
| 719 |
+
template <typename T>
|
| 720 |
+
T recvValue(int socket) {
|
| 721 |
+
T value;
|
| 722 |
+
recvBytes<T>(socket, &value, 1);
|
| 723 |
+
return value;
|
| 724 |
+
}
|
| 725 |
+
|
| 726 |
+
// send a string's length and data
|
| 727 |
+
inline void sendString(
|
| 728 |
+
int socket,
|
| 729 |
+
const std::string& str,
|
| 730 |
+
bool moreData = false) {
|
| 731 |
+
SizeType size = str.size();
|
| 732 |
+
sendBytes<SizeType>(socket, &size, 1, true);
|
| 733 |
+
sendBytes<char>(socket, str.data(), size, moreData);
|
| 734 |
+
}
|
| 735 |
+
|
| 736 |
+
// receive a string as sent in sendString
|
| 737 |
+
inline std::string recvString(int socket) {
|
| 738 |
+
SizeType valueSize = 0;
|
| 739 |
+
recvBytes<SizeType>(socket, &valueSize, 1);
|
| 740 |
+
std::vector<char> value(valueSize);
|
| 741 |
+
recvBytes<char>(socket, value.data(), value.size());
|
| 742 |
+
return std::string(value.data(), value.size());
|
| 743 |
+
}
|
| 744 |
+
|
| 745 |
+
} // namespace tcputil
|
| 746 |
+
} // namespace c10d
|
| 747 |
+
|
| 748 |
+
#else
|
| 749 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 750 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/WinSockUtils.hpp
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <torch/csrc/distributed/c10d/Utils.hpp>
|
| 5 |
+
|
| 6 |
+
namespace c10d::tcputil {
|
| 7 |
+
|
| 8 |
+
#define CONNECT_SOCKET_OFFSET 1
|
| 9 |
+
|
| 10 |
+
inline int poll(struct pollfd* fdArray, unsigned long fds, int timeout) {
|
| 11 |
+
return WSAPoll(fdArray, fds, timeout);
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
inline void addPollfd(
|
| 15 |
+
std::vector<struct pollfd>& fds,
|
| 16 |
+
int socket,
|
| 17 |
+
short events) {
|
| 18 |
+
fds.push_back({(SOCKET)socket, events});
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
inline struct ::pollfd getPollfd(int socket, short events) {
|
| 22 |
+
struct ::pollfd res = {(SOCKET)socket, events};
|
| 23 |
+
return res;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
} // namespace c10d::tcputil
|
| 27 |
+
|
| 28 |
+
#else
|
| 29 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 30 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Work.hpp
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <ATen/ATen.h>
|
| 5 |
+
#include <chrono>
|
| 6 |
+
#include <mutex>
|
| 7 |
+
#include <vector>
|
| 8 |
+
|
| 9 |
+
constexpr auto kNoTimeout = std::chrono::milliseconds(0);
|
| 10 |
+
|
| 11 |
+
namespace c10d {
|
| 12 |
+
|
| 13 |
+
constexpr const char* const kSeqNumStoreKey = "SEQ_NUM_STORE_KEY";
|
| 14 |
+
|
| 15 |
+
enum class OpType : std::uint8_t {
|
| 16 |
+
BROADCAST = 0,
|
| 17 |
+
ALLREDUCE = 1,
|
| 18 |
+
ALLREDUCE_COALESCED = 2,
|
| 19 |
+
REDUCE = 3,
|
| 20 |
+
ALLGATHER = 4,
|
| 21 |
+
_ALLGATHER_BASE = 5,
|
| 22 |
+
ALLGATHER_COALESCED = 6,
|
| 23 |
+
GATHER = 7,
|
| 24 |
+
SCATTER = 8,
|
| 25 |
+
REDUCE_SCATTER = 9,
|
| 26 |
+
ALLTOALL_BASE = 10,
|
| 27 |
+
ALLTOALL = 11,
|
| 28 |
+
SEND = 12,
|
| 29 |
+
RECV = 13,
|
| 30 |
+
RECVANYSOURCE = 14,
|
| 31 |
+
BARRIER = 15,
|
| 32 |
+
_REDUCE_SCATTER_BASE = 16,
|
| 33 |
+
COALESCED = 17,
|
| 34 |
+
_ALLREDUCE_SPARSE = 18,
|
| 35 |
+
REDUCE_SCATTER_TENSOR_COALESCED = 19,
|
| 36 |
+
UNKNOWN = 100,
|
| 37 |
+
};
|
| 38 |
+
|
| 39 |
+
// TODO: support different types of failures/errors
|
| 40 |
+
enum class WorkResult : std::uint8_t {
|
| 41 |
+
SUCCESS = 0,
|
| 42 |
+
TIMEOUT = 1,
|
| 43 |
+
COMM_ERROR = 2,
|
| 44 |
+
UNKNOWN = 100,
|
| 45 |
+
};
|
| 46 |
+
|
| 47 |
+
// Converts OpType to human readable string.
|
| 48 |
+
TORCH_API std::string opTypeToString(OpType opType);
|
| 49 |
+
|
| 50 |
+
// Whether or not an OP is an p2p op (SEND, RECV, RECVANYSOURCE)
|
| 51 |
+
TORCH_API bool isP2POp(OpType opType, bool batchP2P = false);
|
| 52 |
+
|
| 53 |
+
// Please do not use Work API, it is going away, to be
|
| 54 |
+
// replaced by ivalue::Future.
|
| 55 |
+
// Python binding for this class might change, please do not assume
|
| 56 |
+
// this will be bound using pybind.
|
| 57 |
+
class TORCH_API Work : public torch::CustomClassHolder {
|
| 58 |
+
public:
|
| 59 |
+
Work(
|
| 60 |
+
int rank = -1,
|
| 61 |
+
OpType opType = OpType::UNKNOWN,
|
| 62 |
+
const char* profilingTitle = nullptr,
|
| 63 |
+
const std::optional<std::vector<at::Tensor>>& inputTensors =
|
| 64 |
+
std::nullopt);
|
| 65 |
+
|
| 66 |
+
~Work() override;
|
| 67 |
+
|
| 68 |
+
// Checks if request has completed. Non-blocking operation.
|
| 69 |
+
virtual bool isCompleted();
|
| 70 |
+
|
| 71 |
+
// Returns if the work completed successfully.
|
| 72 |
+
// If false, the exception function can be called to get details.
|
| 73 |
+
virtual bool isSuccess() const;
|
| 74 |
+
|
| 75 |
+
// Returns exception if isSuccess() returned false.
|
| 76 |
+
virtual std::exception_ptr exception() const;
|
| 77 |
+
|
| 78 |
+
// Returns source rank if this objects represents a recv-from-any.
|
| 79 |
+
virtual int sourceRank() const;
|
| 80 |
+
|
| 81 |
+
// Returns result tensors, if applicable.
|
| 82 |
+
// If work is not supposed to have result, we return empty list.
|
| 83 |
+
virtual std::vector<at::Tensor> result();
|
| 84 |
+
|
| 85 |
+
// Ensures that operations on the output tensors that are invoked
|
| 86 |
+
// after this function returns are correctly sequenced after the
|
| 87 |
+
// asynchronous completion of this work.
|
| 88 |
+
//
|
| 89 |
+
// For CUDA tensors, it inserts stream synchronization such that
|
| 90 |
+
// the streams of the caller wait for completion of the
|
| 91 |
+
// asynchronous operations on the destination tensors.
|
| 92 |
+
//
|
| 93 |
+
// For CPU tensors, it is currently a nop.
|
| 94 |
+
//
|
| 95 |
+
// This function should only be used if the caller polls for
|
| 96 |
+
// completion through the `isCompleted` function, it has returned
|
| 97 |
+
// true, and the `isSuccess` function also has returned true.
|
| 98 |
+
//
|
| 99 |
+
virtual void synchronize();
|
| 100 |
+
|
| 101 |
+
// Waits until request completes. Blocking operation.
|
| 102 |
+
// Throws if the work completed with an exception.
|
| 103 |
+
// Returns false if the work is aborted.
|
| 104 |
+
// Otherwise, it always returns true, indicating the work is completed.
|
| 105 |
+
//
|
| 106 |
+
// Functionally equivalent to:
|
| 107 |
+
//
|
| 108 |
+
// while (!isCompleted()) { /* nop */ }
|
| 109 |
+
// auto success = isSuccess();
|
| 110 |
+
// if (!success) { std::rethrow_exception(exception()); }
|
| 111 |
+
// return success;
|
| 112 |
+
//
|
| 113 |
+
virtual bool wait(std::chrono::milliseconds timeout = kNoTimeout);
|
| 114 |
+
|
| 115 |
+
// Blocks the current stream until the work is completed.
|
| 116 |
+
// This is equivalent to synchronize for CUDA tensors but works for both CPU
|
| 117 |
+
// tensors and CUDA tensors by using a spinlock CUDA kernel.
|
| 118 |
+
// This will immediately return.
|
| 119 |
+
// If no stream is active it will throw an error.
|
| 120 |
+
virtual void blockCurrentStream();
|
| 121 |
+
|
| 122 |
+
virtual void abort();
|
| 123 |
+
|
| 124 |
+
// Returns a Future object that will be associated with the completion of
|
| 125 |
+
// work. Only NCCL backend is currently supported.
|
| 126 |
+
virtual c10::intrusive_ptr<c10::ivalue::Future> getFuture();
|
| 127 |
+
|
| 128 |
+
// Get a Future object that would be marked as either success or failure
|
| 129 |
+
// This API can be used by the user to track the completion of the work
|
| 130 |
+
// and handle the exception if any.
|
| 131 |
+
virtual c10::intrusive_ptr<c10::ivalue::Future> getFutureResult();
|
| 132 |
+
|
| 133 |
+
virtual float getDuration() const;
|
| 134 |
+
|
| 135 |
+
virtual uint64_t getSequencenumber() const;
|
| 136 |
+
|
| 137 |
+
OpType retrieveOpType() const;
|
| 138 |
+
|
| 139 |
+
static c10::intrusive_ptr<Work> create_from_future(
|
| 140 |
+
const c10::intrusive_ptr<c10::ivalue::Future>& /*future*/);
|
| 141 |
+
|
| 142 |
+
protected:
|
| 143 |
+
// Completes the work object and optionally sets the exception in a
|
| 144 |
+
// thread-safe manner. Notifies all waiting condition variables as well.
|
| 145 |
+
void finish(std::exception_ptr exception = nullptr);
|
| 146 |
+
|
| 147 |
+
// Similar to finish, but throws an exception if one is already set or
|
| 148 |
+
// provided by the user.
|
| 149 |
+
void finishAndThrow(std::exception_ptr exception);
|
| 150 |
+
|
| 151 |
+
mutable std::mutex mutex_;
|
| 152 |
+
std::condition_variable cv_;
|
| 153 |
+
bool completed_ = false;
|
| 154 |
+
std::exception_ptr exception_;
|
| 155 |
+
|
| 156 |
+
// Current rank of the node.
|
| 157 |
+
const int rank_;
|
| 158 |
+
|
| 159 |
+
// Operation type that this work object refers to.
|
| 160 |
+
OpType opType_;
|
| 161 |
+
|
| 162 |
+
// When profiling, the callback to record end of operation event. This
|
| 163 |
+
// callback needs to be called when collective operation is complete.
|
| 164 |
+
std::function<void()> recordFunctionEndCallback_;
|
| 165 |
+
};
|
| 166 |
+
|
| 167 |
+
struct TORCH_API WorkInfo {
|
| 168 |
+
WorkInfo(
|
| 169 |
+
const OpType& opType,
|
| 170 |
+
const uint64_t seq,
|
| 171 |
+
const std::chrono::time_point<std::chrono::steady_clock>& timeStarted,
|
| 172 |
+
const std::chrono::time_point<std::chrono::steady_clock>& timeFinished,
|
| 173 |
+
const std::chrono::duration<float>& activeDuration)
|
| 174 |
+
: opType(opType),
|
| 175 |
+
seq(seq),
|
| 176 |
+
timeStarted(timeStarted),
|
| 177 |
+
timeFinished(timeFinished),
|
| 178 |
+
activeDuration(activeDuration) {}
|
| 179 |
+
|
| 180 |
+
OpType opType;
|
| 181 |
+
uint64_t seq;
|
| 182 |
+
std::chrono::time_point<std::chrono::steady_clock> timeStarted;
|
| 183 |
+
std::chrono::time_point<std::chrono::steady_clock> timeFinished;
|
| 184 |
+
std::chrono::duration<float> activeDuration;
|
| 185 |
+
};
|
| 186 |
+
|
| 187 |
+
TORCH_API void set_comm_profiling_name(const std::string& name);
|
| 188 |
+
TORCH_API const std::string& get_comm_profiling_name();
|
| 189 |
+
|
| 190 |
+
} // namespace c10d
|
| 191 |
+
|
| 192 |
+
#else
|
| 193 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 194 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/c10d.h
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <torch/csrc/python_headers.h>
|
| 5 |
+
|
| 6 |
+
namespace torch::distributed::c10d {
|
| 7 |
+
|
| 8 |
+
PyMethodDef* python_functions();
|
| 9 |
+
|
| 10 |
+
} // namespace torch::distributed::c10d
|
| 11 |
+
|
| 12 |
+
#else
|
| 13 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 14 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/comm.hpp
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <ATen/ATen.h>
|
| 5 |
+
#include <ATen/core/ivalue.h>
|
| 6 |
+
#include <torch/csrc/Export.h>
|
| 7 |
+
#include <torch/csrc/distributed/c10d/ProcessGroup.hpp>
|
| 8 |
+
#include <utility>
|
| 9 |
+
|
| 10 |
+
namespace c10d {
|
| 11 |
+
|
| 12 |
+
// Broadcast many tensors to all processes in the process group.
|
| 13 |
+
TORCH_API void broadcast_coalesced(
|
| 14 |
+
const c10::intrusive_ptr<c10d::ProcessGroup>& process_group,
|
| 15 |
+
at::TensorList tensors,
|
| 16 |
+
size_t buffer_size,
|
| 17 |
+
int rank = 0);
|
| 18 |
+
|
| 19 |
+
// This class passes bucket contents tensor to DDP communication hook.
|
| 20 |
+
class TORCH_API GradBucket {
|
| 21 |
+
public:
|
| 22 |
+
explicit GradBucket(
|
| 23 |
+
size_t index,
|
| 24 |
+
size_t bucket_count,
|
| 25 |
+
at::Tensor tensor,
|
| 26 |
+
std::vector<size_t> offsets,
|
| 27 |
+
std::vector<size_t> lengths,
|
| 28 |
+
std::vector<c10::IntArrayRef> sizes_vec,
|
| 29 |
+
std::vector<at::Tensor> parameters,
|
| 30 |
+
std::optional<at::Tensor> sparse_grad_indices)
|
| 31 |
+
: index_(index),
|
| 32 |
+
bucket_count_(bucket_count),
|
| 33 |
+
buffer_(std::move(tensor)),
|
| 34 |
+
offsets_(std::move(offsets)),
|
| 35 |
+
lengths_(std::move(lengths)),
|
| 36 |
+
sizes_vec_(std::move(sizes_vec)),
|
| 37 |
+
parameters_(std::move(parameters)),
|
| 38 |
+
sparse_grad_indices_(std::move(sparse_grad_indices)) {}
|
| 39 |
+
|
| 40 |
+
// Returns the index of the bucket, which is unique across all the buckets.
|
| 41 |
+
size_t getIndex() const {
|
| 42 |
+
return index_;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
const at::Tensor& getBuffer() const {
|
| 46 |
+
return buffer_;
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
// Returns a mutable buffer compared with the above method.
|
| 50 |
+
at::Tensor& getBufferRef() {
|
| 51 |
+
return buffer_;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
// Overwrites the buffer at a specific index.
|
| 55 |
+
void setBuffer(at::Tensor& buffer) {
|
| 56 |
+
buffer_ = buffer;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
// Each tensor in the list that getGradients corresponds to a
|
| 60 |
+
// parameter.
|
| 61 |
+
std::vector<at::Tensor> getGradients() const;
|
| 62 |
+
|
| 63 |
+
// Returns model parameters belonging to this bucket. They are returned in the
|
| 64 |
+
// same order as gradient tensors via getGradients(). For example,
|
| 65 |
+
// getParameters[i] will have its gradient stored in
|
| 66 |
+
// getGradients[i]
|
| 67 |
+
const std::vector<at::Tensor> getParameters() const {
|
| 68 |
+
return parameters_;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
// Returns whether this bucket is the last bucket to allreduce in an
|
| 72 |
+
// iteration.
|
| 73 |
+
bool isLast() const {
|
| 74 |
+
return index_ == bucket_count_ - 1;
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
std::optional<at::Tensor>& getSparseGradIndices() {
|
| 78 |
+
return sparse_grad_indices_;
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
private:
|
| 82 |
+
size_t index_;
|
| 83 |
+
size_t bucket_count_;
|
| 84 |
+
at::Tensor buffer_;
|
| 85 |
+
|
| 86 |
+
// Per-variable info in buffer_.
|
| 87 |
+
std::vector<size_t> offsets_;
|
| 88 |
+
std::vector<size_t> lengths_;
|
| 89 |
+
std::vector<c10::IntArrayRef> sizes_vec_;
|
| 90 |
+
|
| 91 |
+
// Model parameters for this bucket.
|
| 92 |
+
// NOLINTNEXTLINE(cppcoreguidelines-avoid-const-or-ref-data-members)
|
| 93 |
+
const std::vector<at::Tensor> parameters_;
|
| 94 |
+
|
| 95 |
+
// Predefined sparse indices for this bucket (only used for sparse tensors).
|
| 96 |
+
// The gradients will be updated to have indices with these tensor values
|
| 97 |
+
std::optional<at::Tensor> sparse_grad_indices_;
|
| 98 |
+
};
|
| 99 |
+
|
| 100 |
+
// Base class of both `PythonCommHook` and `CppCommHook`.
|
| 101 |
+
// Requires implementing 1) `runHook` method that communicates gradients
|
| 102 |
+
// asynchronously, and 2) `parseHookResult` method that converts the hook
|
| 103 |
+
// result into a tensor.
|
| 104 |
+
class TORCH_API CommHookInterface {
|
| 105 |
+
public:
|
| 106 |
+
virtual ~CommHookInterface() = default;
|
| 107 |
+
|
| 108 |
+
// Passes the input grad bucket to the registered communication hook.
|
| 109 |
+
// Once the tensor in the bucket are ready, kicks off the hook asynchronously
|
| 110 |
+
// and returns a future that holds the communication results.
|
| 111 |
+
virtual c10::intrusive_ptr<c10::ivalue::Future> runHook(
|
| 112 |
+
GradBucket& bucket) = 0;
|
| 113 |
+
|
| 114 |
+
// Returns the resulting tensor once the communication hook result is
|
| 115 |
+
// ready. The resulting tensor will then be copied to the grads of
|
| 116 |
+
// individual parameters.
|
| 117 |
+
virtual at::Tensor parseHookResult(const c10::IValue& result) = 0;
|
| 118 |
+
};
|
| 119 |
+
|
| 120 |
+
namespace detail {
|
| 121 |
+
// This helper function is called both by CppCommHookInterface below and inside
|
| 122 |
+
// reducer.
|
| 123 |
+
TORCH_API at::Tensor parseCppCommHookResult(const c10::IValue& result);
|
| 124 |
+
} // namespace detail
|
| 125 |
+
|
| 126 |
+
// This CppCommHook interface only requires implementing runHook method that
|
| 127 |
+
// potentially uses a state.
|
| 128 |
+
template <typename T>
|
| 129 |
+
class CppCommHookInterface : public CommHookInterface {
|
| 130 |
+
public:
|
| 131 |
+
explicit CppCommHookInterface(T state) : state_(std::move(state)) {}
|
| 132 |
+
|
| 133 |
+
~CppCommHookInterface() override = default;
|
| 134 |
+
|
| 135 |
+
at::Tensor parseHookResult(const c10::IValue& result) override {
|
| 136 |
+
return detail::parseCppCommHookResult(result);
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
protected:
|
| 140 |
+
T state_;
|
| 141 |
+
};
|
| 142 |
+
|
| 143 |
+
} // namespace c10d
|
| 144 |
+
|
| 145 |
+
#else
|
| 146 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 147 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_collectives/ControlCollectives.hpp
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <ATen/core/ivalue.h>
|
| 5 |
+
#include <chrono>
|
| 6 |
+
#include <cstdint>
|
| 7 |
+
#include <string>
|
| 8 |
+
#include <vector>
|
| 9 |
+
|
| 10 |
+
#include <c10/macros/Macros.h>
|
| 11 |
+
#include <torch/custom_class.h>
|
| 12 |
+
|
| 13 |
+
namespace c10d {
|
| 14 |
+
|
| 15 |
+
using namespace std::chrono_literals;
|
| 16 |
+
|
| 17 |
+
class TORCH_API ControlCollectives : public torch::CustomClassHolder {
|
| 18 |
+
public:
|
| 19 |
+
virtual void barrier(
|
| 20 |
+
const std::string& key,
|
| 21 |
+
std::chrono::milliseconds timeout = 5min,
|
| 22 |
+
bool block = true) = 0;
|
| 23 |
+
|
| 24 |
+
virtual void broadcastSend(
|
| 25 |
+
const std::string& key,
|
| 26 |
+
const std::vector<uint8_t>& data,
|
| 27 |
+
std::chrono::milliseconds timeout = 5min) = 0;
|
| 28 |
+
virtual std::vector<uint8_t> broadcastRecv(
|
| 29 |
+
const std::string& key,
|
| 30 |
+
std::chrono::milliseconds timeout = 5min) = 0;
|
| 31 |
+
|
| 32 |
+
virtual void gatherSend(
|
| 33 |
+
const std::string& key,
|
| 34 |
+
const std::vector<uint8_t>& data,
|
| 35 |
+
std::chrono::milliseconds timeout = 5min) = 0;
|
| 36 |
+
virtual std::vector<std::vector<uint8_t>> gatherRecv(
|
| 37 |
+
const std::string& key,
|
| 38 |
+
const std::vector<uint8_t>& data,
|
| 39 |
+
std::chrono::milliseconds timeout = 5min) = 0;
|
| 40 |
+
|
| 41 |
+
virtual std::vector<uint8_t> scatterSend(
|
| 42 |
+
const std::string& key,
|
| 43 |
+
const std::vector<std::vector<uint8_t>>& data,
|
| 44 |
+
std::chrono::milliseconds timeout = 5min) = 0;
|
| 45 |
+
virtual std::vector<uint8_t> scatterRecv(
|
| 46 |
+
const std::string& key,
|
| 47 |
+
std::chrono::milliseconds timeout = 5min) = 0;
|
| 48 |
+
|
| 49 |
+
virtual std::vector<std::vector<uint8_t>> allGather(
|
| 50 |
+
const std::string& key,
|
| 51 |
+
const std::vector<uint8_t>& data,
|
| 52 |
+
std::chrono::milliseconds timeout = 5min) = 0;
|
| 53 |
+
|
| 54 |
+
virtual int64_t allSum(
|
| 55 |
+
const std::string& key,
|
| 56 |
+
int64_t data,
|
| 57 |
+
std::chrono::milliseconds timeout = 5min) = 0;
|
| 58 |
+
};
|
| 59 |
+
|
| 60 |
+
} // namespace c10d
|
| 61 |
+
|
| 62 |
+
#else
|
| 63 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 64 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_collectives/StoreCollectives.hpp
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <c10/macros/Macros.h>
|
| 5 |
+
#include <c10/util/FbcodeMaps.h>
|
| 6 |
+
#include <torch/csrc/distributed/c10d/Store.hpp>
|
| 7 |
+
#include <torch/csrc/distributed/c10d/control_collectives/ControlCollectives.hpp>
|
| 8 |
+
|
| 9 |
+
namespace c10d {
|
| 10 |
+
|
| 11 |
+
class TORCH_API StoreCollectives : public ControlCollectives {
|
| 12 |
+
public:
|
| 13 |
+
explicit StoreCollectives(
|
| 14 |
+
c10::intrusive_ptr<Store> store,
|
| 15 |
+
int rank,
|
| 16 |
+
int worldSize);
|
| 17 |
+
|
| 18 |
+
void barrier(
|
| 19 |
+
const std::string& key,
|
| 20 |
+
std::chrono::milliseconds timeout = 5min,
|
| 21 |
+
bool block = true) override;
|
| 22 |
+
|
| 23 |
+
void broadcastSend(
|
| 24 |
+
const std::string& key,
|
| 25 |
+
const std::vector<uint8_t>& data,
|
| 26 |
+
std::chrono::milliseconds timeout = 5min) override;
|
| 27 |
+
std::vector<uint8_t> broadcastRecv(
|
| 28 |
+
const std::string& key,
|
| 29 |
+
std::chrono::milliseconds timeout = 5min) override;
|
| 30 |
+
|
| 31 |
+
void gatherSend(
|
| 32 |
+
const std::string& key,
|
| 33 |
+
const std::vector<uint8_t>& data,
|
| 34 |
+
std::chrono::milliseconds timeout = 5min) override;
|
| 35 |
+
std::vector<std::vector<uint8_t>> gatherRecv(
|
| 36 |
+
const std::string& key,
|
| 37 |
+
const std::vector<uint8_t>& data,
|
| 38 |
+
std::chrono::milliseconds timeout = 5min) override;
|
| 39 |
+
|
| 40 |
+
std::vector<uint8_t> scatterSend(
|
| 41 |
+
const std::string& key,
|
| 42 |
+
const std::vector<std::vector<uint8_t>>& data,
|
| 43 |
+
std::chrono::milliseconds timeout = 5min) override;
|
| 44 |
+
std::vector<uint8_t> scatterRecv(
|
| 45 |
+
const std::string& key,
|
| 46 |
+
std::chrono::milliseconds timeout = 5min) override;
|
| 47 |
+
|
| 48 |
+
std::vector<std::vector<uint8_t>> allGather(
|
| 49 |
+
const std::string& key,
|
| 50 |
+
const std::vector<uint8_t>& data,
|
| 51 |
+
std::chrono::milliseconds timeout = 5min) override;
|
| 52 |
+
|
| 53 |
+
int64_t allSum(
|
| 54 |
+
const std::string& key,
|
| 55 |
+
int64_t data,
|
| 56 |
+
std::chrono::milliseconds timeout = 5min) override;
|
| 57 |
+
|
| 58 |
+
private:
|
| 59 |
+
void enforceUnique(const std::string& key);
|
| 60 |
+
|
| 61 |
+
private:
|
| 62 |
+
c10::intrusive_ptr<Store> store_;
|
| 63 |
+
int rank_;
|
| 64 |
+
int worldSize_;
|
| 65 |
+
|
| 66 |
+
c10::FastSet<std::string> seenKeys_;
|
| 67 |
+
};
|
| 68 |
+
|
| 69 |
+
} // namespace c10d
|
| 70 |
+
|
| 71 |
+
#else
|
| 72 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 73 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_plane/Handlers.hpp
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <functional>
|
| 5 |
+
#include <map>
|
| 6 |
+
#include <string>
|
| 7 |
+
#include <utility>
|
| 8 |
+
|
| 9 |
+
#include <c10/macros/Export.h>
|
| 10 |
+
|
| 11 |
+
namespace c10d::control_plane {
|
| 12 |
+
|
| 13 |
+
// Request represents a request to the handler. This conceptually maps to an
|
| 14 |
+
// HTTP request but could be called via other transports.
|
| 15 |
+
class TORCH_API Request {
|
| 16 |
+
public:
|
| 17 |
+
virtual ~Request() = default;
|
| 18 |
+
|
| 19 |
+
virtual const std::string& body() const = 0;
|
| 20 |
+
|
| 21 |
+
virtual const std::multimap<std::string, std::string>& params() const = 0;
|
| 22 |
+
|
| 23 |
+
std::string getParam(const std::string& key) const {
|
| 24 |
+
auto it = params().find(key);
|
| 25 |
+
if (it != params().end()) {
|
| 26 |
+
return it->second;
|
| 27 |
+
}
|
| 28 |
+
return "";
|
| 29 |
+
}
|
| 30 |
+
};
|
| 31 |
+
|
| 32 |
+
// Response represents a response to the handler. This conceptually maps to an
|
| 33 |
+
// HTTP response but could be called via other transports.
|
| 34 |
+
class TORCH_API Response {
|
| 35 |
+
public:
|
| 36 |
+
virtual ~Response() = default;
|
| 37 |
+
|
| 38 |
+
// Set the response body to the provided string.
|
| 39 |
+
// TODO: add support for chunked responses
|
| 40 |
+
virtual void setContent(
|
| 41 |
+
std::string&& content,
|
| 42 |
+
const std::string& content_type) = 0;
|
| 43 |
+
|
| 44 |
+
// Set the response status code.
|
| 45 |
+
// These should match standard HTTP status codes.
|
| 46 |
+
virtual void setStatus(int status) = 0;
|
| 47 |
+
};
|
| 48 |
+
|
| 49 |
+
using HandlerFunc = std::function<void(const Request&, Response&)>;
|
| 50 |
+
|
| 51 |
+
// Registers a handler. The name needs to be unique and can be called by using
|
| 52 |
+
// getHandler directly or via WorkerServer for remote requests.
|
| 53 |
+
// These handlers are called from a background C++ thread concurrently with the
|
| 54 |
+
// main thread. These handlers need to be thread safe and not cause issues
|
| 55 |
+
// during Python training.
|
| 56 |
+
TORCH_API void registerHandler(const std::string& name, HandlerFunc f);
|
| 57 |
+
|
| 58 |
+
// Fetches a handler by name.
|
| 59 |
+
TORCH_API HandlerFunc getHandler(const std::string& name);
|
| 60 |
+
|
| 61 |
+
TORCH_API std::vector<std::string> getHandlerNames();
|
| 62 |
+
|
| 63 |
+
// Registers a handler statically.
|
| 64 |
+
// See registerHandler for more details.
|
| 65 |
+
class TORCH_API RegisterHandler {
|
| 66 |
+
public:
|
| 67 |
+
RegisterHandler(const std::string& name, HandlerFunc f) {
|
| 68 |
+
registerHandler(name, std::move(f));
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
// disable move, copy
|
| 72 |
+
RegisterHandler(const RegisterHandler&) = delete;
|
| 73 |
+
RegisterHandler(RegisterHandler&&) = delete;
|
| 74 |
+
RegisterHandler& operator=(const RegisterHandler&) = delete;
|
| 75 |
+
RegisterHandler& operator=(RegisterHandler&&) = delete;
|
| 76 |
+
};
|
| 77 |
+
|
| 78 |
+
} // namespace c10d::control_plane
|
| 79 |
+
|
| 80 |
+
#else
|
| 81 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 82 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_plane/WaitCounterHandler.hpp
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <string>
|
| 5 |
+
|
| 6 |
+
namespace c10d {
|
| 7 |
+
namespace control_plane {
|
| 8 |
+
|
| 9 |
+
// Returns all wait counter values as a JSON string
|
| 10 |
+
std::string getWaitCounterValuesJson();
|
| 11 |
+
|
| 12 |
+
// Ensures the wait counter backend is registered
|
| 13 |
+
void ensureWaitCounterBackendRegistered();
|
| 14 |
+
|
| 15 |
+
} // namespace control_plane
|
| 16 |
+
} // namespace c10d
|
| 17 |
+
|
| 18 |
+
#else
|
| 19 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 20 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_plane/WorkerServer.hpp
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <string>
|
| 5 |
+
#include <thread>
|
| 6 |
+
|
| 7 |
+
#include <c10/util/intrusive_ptr.h>
|
| 8 |
+
#include <torch/csrc/distributed/c10d/control_plane/Handlers.hpp>
|
| 9 |
+
|
| 10 |
+
C10_DIAGNOSTIC_PUSH_AND_IGNORED_IF_DEFINED("-Wdeprecated-literal-operator")
|
| 11 |
+
#include <httplib.h>
|
| 12 |
+
C10_DIAGNOSTIC_POP()
|
| 13 |
+
|
| 14 |
+
namespace c10d::control_plane {
|
| 15 |
+
|
| 16 |
+
class TORCH_API WorkerServer : public c10::intrusive_ptr_target {
|
| 17 |
+
public:
|
| 18 |
+
WorkerServer(const std::string& hostOrFile, int port = -1);
|
| 19 |
+
~WorkerServer() override;
|
| 20 |
+
|
| 21 |
+
void shutdown();
|
| 22 |
+
|
| 23 |
+
int port() {
|
| 24 |
+
return port_;
|
| 25 |
+
}
|
| 26 |
+
|
| 27 |
+
private:
|
| 28 |
+
httplib::Server server_;
|
| 29 |
+
std::thread serverThread_;
|
| 30 |
+
int port_;
|
| 31 |
+
};
|
| 32 |
+
|
| 33 |
+
} // namespace c10d::control_plane
|
| 34 |
+
|
| 35 |
+
#else
|
| 36 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 37 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/cuda/CUDAEventCache.hpp
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <array>
|
| 5 |
+
#include <deque>
|
| 6 |
+
#include <memory>
|
| 7 |
+
#include <mutex>
|
| 8 |
+
|
| 9 |
+
#include <ATen/cuda/CUDAEvent.h>
|
| 10 |
+
#include <c10/macros/Export.h>
|
| 11 |
+
|
| 12 |
+
namespace c10d {
|
| 13 |
+
|
| 14 |
+
class TORCH_API CUDAEventCache
|
| 15 |
+
: public std::enable_shared_from_this<CUDAEventCache> {
|
| 16 |
+
public:
|
| 17 |
+
CUDAEventCache();
|
| 18 |
+
std::shared_ptr<at::cuda::CUDAEvent> create(bool timing);
|
| 19 |
+
static std::shared_ptr<CUDAEventCache> get(at::DeviceIndex device);
|
| 20 |
+
|
| 21 |
+
private:
|
| 22 |
+
std::mutex cacheMutex_;
|
| 23 |
+
// NOTE: We intentionally store raw pointers so that
|
| 24 |
+
// we do not attempt to destroy the event objects on process exit,
|
| 25 |
+
// because cuda may be gone.
|
| 26 |
+
std::array<std::deque<at::cuda::CUDAEvent*>, 2>
|
| 27 |
+
eventsArray_; // 0 for timing=false, 1 for timing=true
|
| 28 |
+
};
|
| 29 |
+
|
| 30 |
+
} // namespace c10d
|
| 31 |
+
|
| 32 |
+
#else
|
| 33 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 34 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/cuda/StreamBlock.hpp
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
#include <chrono>
|
| 5 |
+
#include <memory>
|
| 6 |
+
|
| 7 |
+
#include <c10/util/Registry.h>
|
| 8 |
+
|
| 9 |
+
namespace c10d::cuda {
|
| 10 |
+
|
| 11 |
+
enum StreamBlockStatus : int32_t {
|
| 12 |
+
UNKNOWN = 0,
|
| 13 |
+
RUNNING = 1,
|
| 14 |
+
TIMED_OUT = 2,
|
| 15 |
+
ABORTED = 3,
|
| 16 |
+
};
|
| 17 |
+
|
| 18 |
+
/*
|
| 19 |
+
StreamBlock implements a baton that will block a the active CUDA stream
|
| 20 |
+
until aborted by the main process.
|
| 21 |
+
*/
|
| 22 |
+
class TORCH_API StreamBlock {
|
| 23 |
+
public:
|
| 24 |
+
virtual ~StreamBlock() = default;
|
| 25 |
+
virtual void abort() = 0;
|
| 26 |
+
virtual StreamBlockStatus status() = 0;
|
| 27 |
+
};
|
| 28 |
+
|
| 29 |
+
std::unique_ptr<StreamBlock> block_stream(std::chrono::milliseconds timeout);
|
| 30 |
+
|
| 31 |
+
// Declare a registry so we can call the CUDA StreamBlock API from CPU only code
|
| 32 |
+
// (i.e. ProcessGroup/Work objects in libtorch_cpu).
|
| 33 |
+
// The implementation lives defined in StreamBlock.cu.
|
| 34 |
+
TORCH_DECLARE_REGISTRY(
|
| 35 |
+
StreamBlockRegistry,
|
| 36 |
+
StreamBlock,
|
| 37 |
+
std::chrono::milliseconds);
|
| 38 |
+
|
| 39 |
+
} // namespace c10d::cuda
|
| 40 |
+
|
| 41 |
+
#else
|
| 42 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 43 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/cuda/utils.hpp
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
#pragma once
|
| 3 |
+
|
| 4 |
+
// This file contains utility functions common for CUDA, which can be used by
|
| 5 |
+
// ProcessGroupNCCL or SymmetricMemory.
|
| 6 |
+
|
| 7 |
+
namespace c10d::cuda {
|
| 8 |
+
|
| 9 |
+
bool deviceSupportsMulticast(int device_idx);
|
| 10 |
+
|
| 11 |
+
} // namespace c10d::cuda
|
| 12 |
+
|
| 13 |
+
#else
|
| 14 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 15 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/debug.h
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#if !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|
| 2 |
+
// Copyright (c) Meta Platforms, Inc. and its affiliates.
|
| 3 |
+
// All rights reserved.
|
| 4 |
+
//
|
| 5 |
+
// This source code is licensed under the BSD-style license found in the
|
| 6 |
+
// LICENSE file in the root directory of this source tree.
|
| 7 |
+
|
| 8 |
+
#pragma once
|
| 9 |
+
|
| 10 |
+
#include <c10/macros/Macros.h>
|
| 11 |
+
|
| 12 |
+
namespace c10d {
|
| 13 |
+
|
| 14 |
+
enum class DebugLevel { Off = 0, Info = 1, Detail = 2 };
|
| 15 |
+
|
| 16 |
+
TORCH_API void setDebugLevel(DebugLevel level);
|
| 17 |
+
|
| 18 |
+
// Sets the debug level based on the value of the `TORCH_DISTRIBUTED_DEBUG`
|
| 19 |
+
// environment variable.
|
| 20 |
+
TORCH_API void setDebugLevelFromEnvironment();
|
| 21 |
+
|
| 22 |
+
TORCH_API DebugLevel debug_level() noexcept;
|
| 23 |
+
|
| 24 |
+
} // namespace c10d
|
| 25 |
+
|
| 26 |
+
#else
|
| 27 |
+
#error "This file should not be included when either TORCH_STABLE_ONLY or TORCH_TARGET_VERSION is defined."
|
| 28 |
+
#endif // !defined(TORCH_STABLE_ONLY) && !defined(TORCH_TARGET_VERSION)
|