anhtld commited on
Commit
c4fa0be
·
verified ·
1 Parent(s): 61db228

auto-sync 2026-07-02T13:37:00Z workspace (part 26)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +6 -0
  2. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/autograd/rpc_messages/rpc_with_profiling_resp.h +63 -0
  3. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/autograd/rpc_messages/rref_backward_req.h +43 -0
  4. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/autograd/rpc_messages/rref_backward_resp.h +22 -0
  5. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/autograd/utils.h +61 -0
  6. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Backend.hpp +559 -0
  7. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Backoff.hpp +57 -0
  8. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/FakeProcessGroup.hpp +258 -0
  9. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/FileStore.hpp +72 -0
  10. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/FlightRecorder.hpp +336 -0
  11. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/FlightRecorderDetail.hpp +641 -0
  12. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Functional.hpp +182 -0
  13. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/GlooDeviceFactory.hpp +40 -0
  14. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/GroupRegistry.hpp +27 -0
  15. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/HashStore.hpp +86 -0
  16. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/NCCLUtils.hpp +458 -0
  17. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/NanCheck.hpp +17 -0
  18. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ParamCommsUtils.hpp +260 -0
  19. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/PrefixStore.hpp +82 -0
  20. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroup.hpp +1037 -0
  21. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupGloo.hpp +508 -0
  22. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupGlooDetail.hpp +679 -0
  23. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupMPI.hpp +278 -0
  24. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupNCCL.hpp +1547 -0
  25. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupUCC.hpp +363 -0
  26. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/ProcessGroupWrapper.hpp +204 -0
  27. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/PyProcessGroup.hpp +361 -0
  28. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/RankLocal.hpp +94 -0
  29. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Store.hpp +172 -0
  30. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/TCPStore.hpp +181 -0
  31. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/TCPStoreBackend.hpp +84 -0
  32. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/TraceUtils.h +324 -0
  33. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Types.hpp +190 -0
  34. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/UCCTracing.hpp +63 -0
  35. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/UCCUtils.hpp +192 -0
  36. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/UnixSockUtils.hpp +30 -0
  37. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Utils.hpp +750 -0
  38. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/WinSockUtils.hpp +30 -0
  39. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/Work.hpp +194 -0
  40. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/c10d.h +14 -0
  41. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/comm.hpp +147 -0
  42. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_collectives/ControlCollectives.hpp +64 -0
  43. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_collectives/StoreCollectives.hpp +73 -0
  44. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_plane/Handlers.hpp +82 -0
  45. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_plane/WaitCounterHandler.hpp +20 -0
  46. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/control_plane/WorkerServer.hpp +37 -0
  47. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/cuda/CUDAEventCache.hpp +34 -0
  48. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/cuda/StreamBlock.hpp +43 -0
  49. workspace/outputs/audit_venv/lib/python3.11/site-packages/torch/include/torch/csrc/distributed/c10d/cuda/utils.hpp +15 -0
  50. 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)