Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
lishen01
Sccl
Commits
571a75b5
Commit
571a75b5
authored
Aug 09, 2025
by
lishen
Browse files
完成全部网络的node建立,以及GPU到GPU的path物理路径搜索
parent
379c4128
Changes
44
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
2274 additions
and
344 deletions
+2274
-344
src/hardware/net/rocm_wrap.cpp
src/hardware/net/rocm_wrap.cpp
+4
-0
src/hardware/net/rocm_wrap.h
src/hardware/net/rocm_wrap.h
+2
-0
src/hardware/topology/bootstrap/bootstrap.cpp
src/hardware/topology/bootstrap/bootstrap.cpp
+555
-153
src/hardware/topology/bootstrap/bootstrap.h
src/hardware/topology/bootstrap/bootstrap.h
+120
-13
src/hardware/topology/bootstrap/bootstrap_utils.cpp
src/hardware/topology/bootstrap/bootstrap_utils.cpp
+0
-64
src/hardware/topology/bootstrap/bootstrap_utils.h
src/hardware/topology/bootstrap/bootstrap_utils.h
+10
-103
src/hardware/topology/bootstrap/physical_links.cpp
src/hardware/topology/bootstrap/physical_links.cpp
+700
-0
src/hardware/topology/bootstrap/physical_links.h
src/hardware/topology/bootstrap/physical_links.h
+88
-0
src/hardware/topology/bootstrap/readme.MD
src/hardware/topology/bootstrap/readme.MD
+169
-0
src/hardware/topology/graph/graph.cpp
src/hardware/topology/graph/graph.cpp
+45
-0
src/hardware/topology/graph/graph.h
src/hardware/topology/graph/graph.h
+34
-0
src/hardware/topology/graph/graph_utils.cpp
src/hardware/topology/graph/graph_utils.cpp
+13
-0
src/hardware/topology/graph/graph_utils.h
src/hardware/topology/graph/graph_utils.h
+18
-0
src/hardware/topology/graph/paths.cpp
src/hardware/topology/graph/paths.cpp
+368
-0
src/hardware/topology/graph/paths.h
src/hardware/topology/graph/paths.h
+52
-0
src/hardware/topology/graph/readme.MD
src/hardware/topology/graph/readme.MD
+20
-0
src/hardware/topology/topo_utils.cpp
src/hardware/topology/topo_utils.cpp
+51
-0
src/hardware/topology/topo_utils.h
src/hardware/topology/topo_utils.h
+17
-4
src/include/base.h
src/include/base.h
+1
-0
src/include/check.h
src/include/check.h
+7
-7
No files found.
src/hardware/net/rocm_wrap.cpp
View file @
571a75b5
...
...
@@ -83,6 +83,7 @@ static void initOnceFunc() {
WARN
(
"pfn_hsa_system_get_info failed with %d"
,
res
);
goto
error
;
}
res
=
pfn_hsa_system_get_info
(
HSA_SYSTEM_INFO_VERSION_MINOR
,
&
version_minor
);
if
(
res
!=
0
)
{
WARN
(
"pfn_hsa_system_get_info failed with %d"
,
res
);
...
...
@@ -162,6 +163,7 @@ static void initOnceFunc() {
*/
initResult
=
scclSuccess
;
return
;
error:
initResult
=
scclSystemError
;
...
...
@@ -182,6 +184,8 @@ scclResult_t rocmLibraryInit() {
return
rocm_wrap
::
initResult
;
}
int64_t
getDmaBufEnable
()
{
return
rocm_wrap
::
scclParamDmaBufEnable
();
}
}
// namespace net
}
// namespace hardware
}
// namespace sccl
src/hardware/net/rocm_wrap.h
View file @
571a75b5
...
...
@@ -25,6 +25,8 @@ DECLARE_ROCM_PFN_EXTERN(hsa_status_string);
// 初始化 ROCm 库
scclResult_t
rocmLibraryInit
(
void
);
// 获取 dma buf
int64_t
getDmaBufEnable
();
}
// namespace net
}
// namespace hardware
...
...
src/hardware/topology/bootstrap/bootstrap.cpp
View file @
571a75b5
This diff is collapsed.
Click to expand it.
src/hardware/topology/bootstrap/bootstrap.h
View file @
571a75b5
...
...
@@ -7,37 +7,139 @@
#include "bootstrap_net.h"
#include "thread_pool.h"
#include "ipc_socket.h"
#include "physical_links.h"
namespace
sccl
{
namespace
hardware
{
namespace
topology
{
namespace
bootstrap
{
typedef
class
sccl
::
hardware
::
net
::
ipc_socket
::
scclIpcSocket
scclIpcSocket_t
;
typedef
sccl
::
hardware
::
net
::
ipc_socket
::
scclIpcSocket_t
scclIpcSocket_t
;
typedef
physical_links
::
scclTopoNode_t
scclTopoNode_t
;
///////////////////////////////////// 用于初始化时的功能函数 //////////////////////////////////////////
scclResult_t
bootstrapGetUniqueId
(
struct
BootstrapHandle
*
handle
);
scclResult_t
bootstrapCreateRoot
(
struct
BootstrapHandle
*
handle
);
scclResult_t
bootstrapGetUniqueId
(
BootstrapHandle_t
*
handle
);
scclResult_t
bootstrapCreateRoot
(
BootstrapHandle_t
*
handle
);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 定义结构体 scclRankInfo,用于存储每个rank的通信节点的信息
// 每个rank必定选定一个GPU、一个RDMA设备、一个CPU,作为通信节点
typedef
struct
scclRankInfo
{
struct
{
scclSocket_t
listen_sock
;
// 监听套接字
}
cpu
;
// CPU节点
struct
{
int
dev
;
// NVML设备编号
char
name
[
8
];
// 设备名称
char
gcn
[
8
];
// GCN架构名称
int
compCap
;
// CUDA计算能力
int64_t
pciBusId
;
// PCI总线ID以int64_t格式表示
char
pciPath
[
128
];
// PCI设备在/sys中的路径。
}
gpu
;
// GPU节点
struct
{
int
count
;
// 网卡数量
char
name
[
8
];
// 主要用于日志记录。
char
pciPath
[
128
];
// PCI设备在/sys中的路径。
uint64_t
guid
;
// NIC芯片的唯一标识符。对于具有多个PCI功能(物理或虚拟)的卡非常重要。
uint8_t
ptrSupport
;
// [SCCL_PTR_HOST|SCCL_PTR_CUDA|SCCL_PTR_DMABUF]
int
speed
;
// 端口速度,单位为Mbps。
int
port
;
// 端口号。
float
latency
;
// 网络延迟
int
maxComms
;
// 可以创建的最大通信数量
int
maxRecvs
;
// 最大分组接收数量。
}
net
;
// 网络节点
int
rank
=
-
1
;
// 当前节点的全局排名
int
localRank
=
-
1
;
// 当前节点在本地计算节点中的排名
uint64_t
hostHash
=
0
;
// 主机哈希值
uint64_t
pidHash
=
0
;
// 进程 ID 哈希值
}
scclRankInfo_t
;
// 定义结构体 scclNodeInfo,用于存储每个rank的图连接信息
// TODO: 目前每个rank需要的node_info大小为4k+,当卡数较大时占用内存较大,可以优化。或者不作为全局变量
typedef
struct
scclNodeInfo
{
scclTopoNode_t
*
nodes
;
// 指向scclTopoNode_t对象数组的指针
int
nLocalRanks
;
int
totalByteSize
;
// 表示占用的总字节数
// 带参数的构造函数,用于初始化nodes的大小
scclNodeInfo
(
int
nLocalRanks
)
:
nodes
(
nullptr
),
nLocalRanks
(
nLocalRanks
),
totalByteSize
(
sizeof
(
scclTopoNode_t
)
*
topoNodeMaxLocalNodes
/
nLocalRanks
)
{
nodes
=
reinterpret_cast
<
scclTopoNode_t
*>
(
malloc
(
totalByteSize
));
if
(
nodes
)
{
memset
(
nodes
,
0
,
totalByteSize
);
}
}
// 析构函数,用于释放申请的数组空间
virtual
~
scclNodeInfo
()
{
if
(
nodes
)
{
free
(
nodes
);
}
}
}
scclNodeInfo_t
;
// 所有节点的信息
typedef
struct
scclRankPhysSet
{
// 构造函数声明
scclRankPhysSet
(
int
nRanks
,
int
nLocalRanks
);
std
::
vector
<
scclRankInfo_t
>
rank_info_vec
;
std
::
vector
<
char
>
node_info_vec
;
// 实际为std::vector<scclNodeInfo_t>,vector不支持scclNodeInfo_t变长
public:
int
nRanks
=
0
;
// 总的节点数量
int
nLocalRanks
=
0
;
// 本地计算节点中的节点总数
size_t
node_info_total_bytes
=
0
;
// 记录可变长度scclNodeInfo_t类型数据的实际大小
}
scclRankPhysSet_t
;
// BootstrapComm 结构体定义,用于存储引导通信信息
typedef
struct
BootstrapComm
{
void
init
(
int
rank
,
int
nRanks
,
int
localRank
,
int
nLocalRanks
);
void
destroy
();
public:
scclNet_t
*
scclNet
=
nullptr
;
scclRankPhysSet_t
*
rank_phys_set
=
nullptr
;
cpu_set_t
cpuAffinity
;
// CPU亲和性
int
rank
=
-
1
;
// 当前节点的全局排名
int
nRanks
=
0
;
// 总的节点数量
int
localRank
=
-
1
;
// 当前节点在本地计算节点中的排名
int
nLocalRanks
=
0
;
// 本地计算节点中的节点总数
int
interRank
=
-
1
;
// 整个节点在全部节点中的位置
int
nInterRanks
=
0
;
// 全局拥有节点的个数
int
hipDev
=
-
1
;
// CUDA 设备 ID
int
deviceCnt
=
0
;
// 设备数量
uint64_t
magic
;
// 魔术数,用于验证结构体
}
BootstrapComm_t
;
///////////////////////////////////// 用于初始化时的类 //////////////////////////////////////////
class
Bootstrap
{
public:
Bootstrap
(
const
struct
BootstrapHandle
*
,
int
rank
,
int
nRanks
);
Bootstrap
(
const
BootstrapHandle
_t
*
,
int
rank
,
int
nRanks
);
~
Bootstrap
();
// 初始化bootstrap通信环境
scclResult_t
init
(
struct
BootstrapComm
*
bootstrap_comm
);
scclResult_t
init
(
BootstrapComm_t
*
bootstrap_comm
);
// 实现跨节点的AllGather通信操作
scclResult_t
bootstrapAllGather
(
const
void
*
src_data
,
void
*
dst_data
,
int
data_size
);
private:
//
创建
根节点的
数据广播
scclResult_t
bootstrapRootGatherAndBroadcast
(
struct
BootstrapNodeBasic
*
send
_data_basic
,
std
::
vector
<
struct
BootstrapNodeBasic
>&
recv
_data_basic
);
//
执行
根节点的
聚集和广播操作
scclResult_t
bootstrapRootGatherAndBroadcast
(
BootstrapNodeBasic
_t
*
send_data_basic
);
// 初始化
唯一ID信息结构体
scclResult_t
bootstrapCommInitNodeInfo
(
scclNet_t
*
scclNet
,
s
truct
scclNodeInfo
*
node
_info
);
// 初始化
节点通信信息
scclResult_t
bootstrapCommInitNodeInfo
(
scclNet_t
*
scclNet
,
s
cclRankInfo_t
*
rank
_info
);
// 广播节点信息
scclResult_t
bootstrapCommAllGather
(
std
::
vector
<
struct
BootstrapNodeBasic
>&
all_node_basic
,
struct
scclNodeInfo
*
node_info
,
struct
scclNodeInfoSet
*
node_info_set
);
// 实现rank_info信息的节点间通信的AllGather操作
scclResult_t
bootstrapCommAllGather
(
scclRankInfo_t
*
rank_info
,
scclNodeInfo_t
*
node_info
,
scclRankPhysSet_t
*
rank_phys_set
);
// 额外处理nRanks个nodes的连接关系
scclResult_t
bootstrapNodesLink
(
void
*
node_info_vec
,
int
node_info_total_bytes
);
private:
int
rank
,
nRanks
;
// 初始化阶段获取MPI的值
...
...
@@ -48,7 +150,9 @@ private:
volatile
uint32_t
*
abortFlag
;
// 中止标志,非阻塞套接字设置
// 外部传入的0号节点的基础信息
const
struct
BootstrapHandle
*
root_handle
;
const
BootstrapHandle_t
*
root_handle
;
// 节点内所有进程的基础ip信息
BootstrapNodeBasic_t
*
all_node_basic
=
nullptr
;
// 初始化标志
bool
socketInitDone
;
...
...
@@ -60,6 +164,9 @@ private:
scclIpcSocket_t
*
ipcsocket
=
nullptr
;
// 指向scclIpcSocket类实例的指针,初始值为nullptr
};
// 打印唯一的拓扑信息
scclResult_t
printRankInfo
(
const
std
::
string
&
prefix
,
scclRankInfo_t
*
info
);
}
// namespace bootstrap
}
// namespace topology
}
// namespace hardware
...
...
src/hardware/topology/bootstrap/bootstrap_utils.cpp
View file @
571a75b5
...
...
@@ -7,32 +7,6 @@ namespace hardware {
namespace
topology
{
namespace
bootstrap
{
////////////////////////////// 结构体定义 //////////////////////////////
// 构造函数定义
scclNodeInfoSet
::
scclNodeInfoSet
(
int
nRanks
)
{
printf
(
"scclNodeInfoSet 构造函数
\n
"
);
node_info_vec
.
reserve
(
nRanks
);
// 预留空间
printf
(
"scclNodeInfoSet 预留空间
\n
"
);
}
void
BootstrapComm
::
init
(
int
rank
,
int
nRanks
,
int
localRank
,
int
nLocalRanks
)
{
printf
(
"BootstrapComm 构造函数, rank=%d
\n
"
,
rank
);
this
->
rank
=
rank
;
this
->
nRanks
=
nRanks
;
this
->
localRank
=
localRank
;
this
->
nLocalRanks
=
nLocalRanks
;
this
->
interRank
=
rank
/
nLocalRanks
;
this
->
nInterRanks
=
nRanks
/
nLocalRanks
;
node_info_set
=
new
scclNodeInfoSet
(
nRanks
);
// 假设需要动态分配
};
void
BootstrapComm
::
destroy
()
{
printf
(
"BootstrapComm 析构函数, rank=%d
\n
"
,
rank
);
if
(
node_info_set
)
{
delete
node_info_set
;
// 释放动态分配的内存
}
}
//////////////////////////////////////////////////////////////////////////////////////////
/**
...
...
@@ -193,44 +167,6 @@ scclResult_t getBusId(int hipDev, int64_t* busId) {
return
scclSuccess
;
}
// 函数:打印 scclNodeInfo 结构体的信息
scclResult_t
printNodeInfo
(
const
std
::
string
&
prefix
,
struct
scclNodeInfo
*
info
)
{
char
addrline
[
net
::
SOCKET_NAME_MAXLEN
+
1
];
// if(info->localRank == 0) {
if
(
1
)
{
printf
(
"==========================================
\n
"
"%s, Total Rank: %d, Local Rank: %d, Host Hash: %lu, PID Hash: %lu
\n
"
"gpu: dev=%d, gpu.name=%s, gcn=%s, compCap=%d
\n
"
"net: count=%d, device name=%s, pciPath=%s, guid=%lu, ptrSupport=%u, speed=%d, port=%d, latency=%f, maxComms=%d, maxRecvs=%d
\n
"
"cpu: socketAddr=%s
\n
pci: busId=%ld"
"
\n
==========================================
\n
"
,
prefix
.
c_str
(),
info
->
rank
,
info
->
localRank
,
info
->
hostHash
,
info
->
pidHash
,
info
->
localNode
.
gpu
.
dev
,
info
->
localNode
.
gpu
.
name
,
info
->
localNode
.
gpu
.
gcn
,
info
->
localNode
.
gpu
.
compCap
,
info
->
localNode
.
net
.
count
,
info
->
localNode
.
net
.
name
,
info
->
localNode
.
net
.
pciPath
,
info
->
localNode
.
net
.
guid
,
static_cast
<
unsigned
int
>
(
info
->
localNode
.
net
.
ptrSupport
),
info
->
localNode
.
net
.
speed
,
info
->
localNode
.
net
.
port
,
info
->
localNode
.
net
.
latency
,
info
->
localNode
.
net
.
maxComms
,
info
->
localNode
.
net
.
maxRecvs
,
net
::
net_socket
::
scclSocketToString
(
&
info
->
localNode
.
cpu
.
listen_sock
.
addr
,
addrline
),
info
->
localNode
.
pci
.
busId
);
}
return
scclSuccess
;
}
}
// namespace bootstrap
}
// namespace topology
}
// namespace hardware
...
...
src/hardware/topology/bootstrap/bootstrap_utils.h
View file @
571a75b5
#pragma once
#include <string.h>
#include <map>
#include <string>
#include <cstddef>
#include <vector>
#include "base.h"
...
...
@@ -17,106 +18,31 @@ typedef union net::net_socket::scclSocketAddress scclSocketAddress_t;
typedef
struct
net
::
net_socket
::
scclSocket
scclSocket_t
;
typedef
net
::
scclNet_t
scclNet_t
;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 用于初始化时广播0号rank的地址信息
struct
BootstrapHandle
{
typedef
struct
BootstrapHandle
{
uint64_t
magic
=
0
;
// 随机码,用于socket通信
scclSocketAddress_t
addr
;
// 地址,用于网络通信
};
}
BootstrapHandle_t
;
#define SCCL_UNIQUE_ID_BYTES (40) // sizeof(BootstrapHandle)
#define SCCL_UNIQUE_ID_BYTES (40) // sizeof(BootstrapHandle
_t
)
typedef
struct
{
char
internal
[
SCCL_UNIQUE_ID_BYTES
];
}
scclUniqueId
;
// 仅用于初始化的函数bootstrapCreateRoot,用于传递detach线程的参数
struct
bootstrapRootArgs
{
typedef
struct
bootstrapRootArgs
{
uint64_t
magic
;
scclSocket_t
*
listenSock
=
nullptr
;
// 根节点的监听
};
}
bootstrapRootArgs_t
;
// 用于初始建立连接阶段,0号rank之外的进程向其传递的信息
struct
BootstrapNodeBasic
{
typedef
struct
BootstrapNodeBasic
{
int
rank
;
int
nRanks
;
// 进程的总数量
uint64_t
hostHash
;
// 用于区分host的CPU编号
scclSocket_t
sock
;
// 各个进程的监听套接字地址,用于网络通信
};
// 定义每个rank所持有的所有拓扑节点
struct
topoLocalNode
{
struct
{
scclSocket_t
listen_sock
;
// 监听套接字
}
cpu
;
// CPU节点
struct
{
int64_t
busId
;
// PCI总线ID以int64_t格式表示
}
pci
;
// pci节点
struct
{
int
dev
;
// NVML设备编号
char
name
[
8
];
// 设备名称
char
gcn
[
8
];
// GCN架构名称
int
compCap
;
// CUDA计算能力
}
gpu
;
// GPU节点
struct
{
int
count
;
// 网卡数量
char
name
[
8
];
// 主要用于日志记录。
char
pciPath
[
128
];
// PCI设备在/sys中的路径。
uint64_t
guid
;
// NIC芯片的唯一标识符。对于具有多个PCI功能(物理或虚拟)的卡非常重要。
uint8_t
ptrSupport
;
// [SCCL_PTR_HOST|SCCL_PTR_CUDA|SCCL_PTR_DMABUF]
int
speed
;
// 端口速度,单位为Mbps。
int
port
;
// 端口号。
float
latency
;
// 网络延迟
int
maxComms
;
// 可以创建的最大通信数量
int
maxRecvs
;
// 最大分组接收数量。
}
net
;
// 网络节点
};
// 定义结构体 scclNodeInfo,用于存储每个rank的通信节点的信息
struct
scclNodeInfo
{
struct
topoLocalNode
localNode
;
int
rank
=
-
1
;
// 当前节点的全局排名
int
localRank
=
-
1
;
// 当前节点在本地计算节点中的排名
uint64_t
hostHash
=
0
;
// 主机哈希值
uint64_t
pidHash
=
0
;
// 进程 ID 哈希值
};
// 每个节点的信息
struct
scclNodeInfoSet
{
std
::
vector
<
struct
scclNodeInfo
>
node_info_vec
;
// 构造函数声明
scclNodeInfoSet
(
int
nRanks
);
};
// BootstrapComm 结构体定义,用于存储引导通信信息
struct
BootstrapComm
{
void
init
(
int
rank
,
int
nRanks
,
int
localRank
,
int
nLocalRanks
);
void
destroy
();
public:
scclNet_t
*
scclNet
;
struct
scclNodeInfoSet
*
node_info_set
;
cpu_set_t
cpuAffinity
;
// CPU亲和性
int
rank
=
-
1
;
// 当前节点的全局排名
int
nRanks
=
0
;
// 总的节点数量
int
localRank
=
-
1
;
// 当前节点在本地计算节点中的排名
int
nLocalRanks
=
0
;
// 本地计算节点中的节点总数
int
interRank
=
-
1
;
// 整个节点在全部节点中的位置
int
nInterRanks
=
0
;
// 全局拥有节点的个数
int
hipDev
=
-
1
;
// CUDA 设备 ID
int
deviceCnt
=
0
;
// 设备数量
// proxy通信
uint64_t
magic
;
// 魔术数,用于验证结构体
volatile
uint32_t
*
abortFlag
;
// 中止标志,非阻塞套接字设置
// int splitShare; // 是否使用共享内存进行分割
// int* topParentRanks; // 顶级父节点的rank
// /* 与代理相关的共享资源 */
// struct scclProxyState* proxyState;
};
}
BootstrapNodeBasic_t
;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 获取主机唯一标识的哈希值,该哈希值在裸机和容器实例中都是唯一的
...
...
@@ -134,25 +60,6 @@ scclResult_t getBusId(int hipDev, int64_t* busId);
// 获取当前HIP设备的计算能力版本号
int
scclCudaCompCap
(
void
);
// 打印唯一的拓扑信息
scclResult_t
printNodeInfo
(
const
std
::
string
&
prefix
,
struct
scclNodeInfo
*
info
);
// 实现类似于std::span的功能,将字节数组转换为类型数组
template
<
typename
T
>
class
ByteSpan
{
public:
ByteSpan
(
const
char
*
data
,
std
::
size_t
size
)
:
data_
(
reinterpret_cast
<
const
T
*>
(
data
)),
size_
(
size
/
sizeof
(
T
))
{}
const
T
*
data
()
const
{
return
data_
;
}
std
::
size_t
size
()
const
{
return
size_
;
}
const
T
&
operator
[](
std
::
size_t
index
)
const
{
return
data_
[
index
];
}
private:
const
T
*
data_
;
std
::
size_t
size_
;
};
}
// namespace bootstrap
}
// namespace topology
}
// namespace hardware
...
...
src/hardware/topology/bootstrap/physical_links.cpp
0 → 100644
View file @
571a75b5
This diff is collapsed.
Click to expand it.
src/hardware/topology/bootstrap/physical_links.h
0 → 100644
View file @
571a75b5
#pragma once
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <string>
#include <array>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <vector>
#include <filesystem> // 需要C++17支持
#include "container.h"
#include "bootstrap_utils.h"
namespace
sccl
{
namespace
hardware
{
namespace
topology
{
namespace
bootstrap
{
constexpr
size_t
topoNodeMaxLocalNodes
=
128
;
// 每个节点最多的node数量
constexpr
size_t
topoNodeMaxNeighbors
=
16
;
// 每个node最多neighbor数量
namespace
physical_links
{
/*
用于生成硬件之间的图点连接关系
依赖于读取/sys/devices 文件夹下的文件来获取信息
例如: /sys/devices/pci0000:98/0000:98:00.0 文件夹下包含各种信息
*/
typedef
struct
scclTopoNode
{
// 构造函数声明
scclTopoNode
();
scclTopoNode
(
const
char
*
pciPath
,
int
interRank
,
int
terminalType
,
int
hipDev
=
-
1
,
int
numaId
=
-
1
);
scclTopoNode
(
int
numaId
,
int
interRank
);
// 添加邻近图点
void
addNeighbor
(
uint64_t
neighborId
);
// 设置busId的字符串
void
setBusIdStr
(
const
char
*
busIdStr
);
// 合并两个具有相同id、type和busIdStr的节点
scclResult_t
combineNode
(
struct
scclTopoNode
*
other_node
);
// 清空节点
void
clearNode
();
// 打印图点信息
void
printNodeInfo
(
const
char
*
prefix
,
bool
printNeighbor
=
false
);
public:
uint64_t
id
;
// 图点id标志
int
type
;
// 图点类型,对应 nodeType_t
int64_t
busId
;
// 总线ID字符串 "0000:00:00.0",例如 "0000:98:03.7",通过int64ToBusId和busIdToInt64变化
int
speed
;
// 速度
int
width
;
// 带宽
std
::
array
<
uint64_t
,
topoNodeMaxNeighbors
>
neighbors
;
// 邻居图点
size_t
neighborCount
;
// 邻居图点的数量
}
scclTopoNode_t
;
// 根据给定的PCI路径生成拓扑节点
scclResult_t
generate_topo_nodes
(
const
char
*
pciPath
,
int
interRank
,
int
hipDev
,
ByteSpanVector
<
scclTopoNode_t
>&
nodes_span
);
// 根据numaId获取pci路径
std
::
string
generate_topo_node_numa_info
(
int
numaId
);
// 输出id分解后的所有数据
void
getIdComponents
(
uint64_t
idToDecompose
,
int
*
interRank
=
nullptr
,
int
*
deviceValue
=
nullptr
,
int
*
terminalType
=
nullptr
,
int
*
hipDev
=
nullptr
,
int
*
numaId
=
nullptr
);
// 获取GPU和NIC的dev对应路径
char
*
getGpuPciPath
(
int
hipDev
);
char
*
getNetPciPath
(
scclNet_t
*
scclNet
,
int
hipDev
);
// 打印拓扑节点的信息
void
printTopoNode
(
ByteSpanArray
<
scclTopoNode_t
>&
nodes
,
int
nodeIndex
,
const
char
*
prefix
);
}
// namespace physical_links
}
// namespace bootstrap
}
// namespace topology
}
// namespace hardware
}
// namespace sccl
src/hardware/topology/bootstrap/readme.MD
0 → 100644
View file @
571a75b5
# SCCL 引导模块文档
## 概述
SCCL引导模块负责在分布式系统中跨多个节点初始化通信环境。该模块处理节点的唯一标识、通信的根节点建立以及通信结构的初始化。核心功能封装在
[
bootstrap.h
](
bootstrap.h
)
头文件中,其对应的实现位于
[
bootstrap.cpp
](
bootstrap.cpp
)
。辅助功能由
[
bootstrap_net.cpp
](
bootstrap_net.cpp
)
、
[
bootstrap_utils.cpp
](
bootstrap_utils.cpp
)
和
[
physical_links.cpp
](
physical_links.cpp
)
提供。
## 核心组件
### 1. BootstrapHandle_t 结构体
[
BootstrapHandle_t
](
bootstrap_utils.h#26
)
结构体用于存储节点的唯一识别信息,包括用于套接字通信的魔数和用于网络通信的套接字地址。
```
c++
typedef
struct
BootstrapHandle
{
uint64_t
magic
;
// 随机数,用于套接字通信
scclSocketAddress_t
addr
;
// 地址,用于网络通信
}
BootstrapHandle_t
;
```
### 2. scclRankInfo_t 结构体
`scclRankInfo_t`
结构体存储每个排名的通信节点信息,包括GPU、RDMA(网络)和CPU节点。
```
c++
typedef
struct
scclRankInfo
{
struct
{
scclSocket_t
listen_sock
;
// 监听套接字
}
cpu
;
struct
{
int
dev
;
char
name
[
8
];
char
gcn
[
8
];
int
compCap
;
int64_t
pciBusId
;
char
pciPath
[
128
];
}
gpu
;
struct
{
int
count
;
char
name
[
8
];
char
pciPath
[
128
];
uint64_t
guid
;
uint8_t
ptrSupport
;
int
speed
;
int
port
;
float
latency
;
int
maxComms
;
int
maxRecvs
;
}
net
;
int
rank
;
int
localRank
;
uint64_t
hostHash
;
uint64_t
pidHash
;
}
scclRankInfo_t
;
```
### 3. scclNodeInfo_t 结构体
`scclNodeInfo_t`
结构体用于存储每个排名的拓扑连接信息。
```
c++
typedef
struct
scclNodeInfo
{
scclTopoNode_t
nodes
[
topoNodeMaxLocalNodes
];
}
scclNodeInfo_t
;
```
### 4. BootstrapComm 结构体
`BootstrapComm`
结构体存储引导通信信息,包括网络属性、排名信息及其他相关数据。
```
c++
typedef
struct
BootstrapComm
{
void
init
(
int
rank
,
int
nRanks
,
int
localRank
,
int
nLocalRanks
);
void
destroy
();
public:
scclNet_t
*
scclNet
;
scclRankPhysSet_t
*
rank_phys_set
;
cpu_set_t
cpuAffinity
;
int
rank
;
int
nRanks
;
int
localRank
;
int
nLocalRanks
;
int
interRank
;
int
nInterRanks
;
int
hipDev
;
int
deviceCnt
;
uint64_t
magic
;
}
BootstrapComm_t
;
```
### 5. Bootstrap 类
`Bootstrap`
类封装了引导初始化过程,包括唯一ID生成、根创建和通信初始化。
```
c++
class
Bootstrap
{
public:
Bootstrap
(
const
BootstrapHandle_t
*
,
int
rank
,
int
nRanks
);
~
Bootstrap
();
scclResult_t
init
(
BootstrapComm_t
*
bootstrap_comm
);
scclResult_t
bootstrapAllGather
(
const
void
*
src_data
,
void
*
dst_data
,
int
data_size
);
private:
scclResult_t
bootstrapRootGatherAndBroadcast
(
BootstrapNodeBasic_t
*
send_data_basic
);
scclResult_t
bootstrapCommInitNodeInfo
(
scclNet_t
*
scclNet
,
scclRankInfo_t
*
rank_info
);
scclResult_t
bootstrapCommAllGather
(
scclRankInfo_t
*
rank_info
,
scclNodeInfo_t
*
node_info
,
scclRankPhysSet_t
*
rank_phys_set
);
scclResult_t
bootstrapNodesLink
(
scclNodeInfo_t
*
node_infos
);
private:
int
rank
,
nRanks
;
int
localRank
,
nLocalRanks
;
int
interRank
,
nInterRanks
;
volatile
uint32_t
*
abortFlag
;
const
BootstrapHandle_t
*
root_handle
;
BootstrapNodeBasic_t
*
all_node_basic
;
bool
socketInitDone
;
pthread_mutex_t
bootstrapMutex
;
pthread_cond_t
bootstrapCond
;
scclIpcSocket_t
*
ipcsocket
;
};
```
## 功能描述
### bootstrapGetUniqueId
该函数为引导过程生成一个唯一ID,利用
`BootstrapHandle_t`
结构体,它初始化引导网络并为通信设置根句柄。
```
c++
scclResult_t
bootstrapGetUniqueId
(
BootstrapHandle_t
*
handle
);
```
### bootstrapCreateRoot
负责为引导过程创建根节点。该函数设置根节点的监听套接字并启动引导通信。
```
c++
scclResult_t
bootstrapCreateRoot
(
BootstrapHandle_t
*
handle
);
```
### Bootstrap::init
`Bootstrap`
类的init方法是核心初始化函数。它设置通信环境,收集并广播排名信息,初始化节点信息,并建立节点连接。
```
c++
scclResult_t
Bootstrap
::
init
(
BootstrapComm_t
*
bootstrap_comm
);
```
## 辅助模块
-
[
bootstrap_net.cpp
](
bootstrap_net.cpp
)
处理与引导相关的网络操作,包括节点之间的套接字通信和数据传输。
-
[
bootstrap_utils.cpp
](
bootstrap_utils.cpp
)
为引导过程提供实用函数,例如哈希、随机数据生成和PCI设备ID检索。
-
[
physical_links.cpp
](
physical_links.cpp
)
定义
`scclTopoNode`
结构体及关联函数,用于生成和管理拓扑节点及其连接。
## 结论
SCCL引导模块为在分布式计算环境中初始化和管理通信提供了一个强大的框架。
通过封装网络通信的复杂性、唯一ID生成和拓扑节点管理,它简化了可扩展和高效通信集合的开发。
src/hardware/topology/graph/graph.cpp
0 → 100644
View file @
571a75b5
#include <iostream>
#include "graph.h"
#include "paths.h"
namespace
sccl
{
namespace
hardware
{
namespace
topology
{
namespace
graph
{
Graph
::
Graph
(
int
rank
,
int
nRanks
)
{
// 构造函数的实现
}
Graph
::~
Graph
()
{
// 析构函数的实现
}
scclResult_t
Graph
::
calculateCommunicationPaths
(
const
BootstrapComm_t
*
bootstrap_comm
)
{
// 通信路径计算的实现
std
::
cout
<<
"Calculating communication paths..."
<<
std
::
endl
;
// 具体的实现细节
auto
path_finder
=
PathFinder
(
bootstrap_comm
);
path_finder
.
findGpuPaths
();
return
scclSuccess
;
}
scclResult_t
Graph
::
buildLogicalTopology
()
{
// 逻辑拓扑构建的实现
std
::
cout
<<
"Building logical topology..."
<<
std
::
endl
;
// 具体的实现细节
return
scclSuccess
;
}
scclResult_t
Graph
::
calculateTopoChannels
()
{
// 根据无向图计算topo路径的实现
std
::
cout
<<
"Calculating topo paths based on undirected graph..."
<<
std
::
endl
;
// 具体的实现细节
return
scclSuccess
;
}
}
// namespace graph
}
// namespace topology
}
// namespace hardware
}
// namespace sccl
src/hardware/topology/graph/graph.h
0 → 100644
View file @
571a75b5
#pragma once
#include <vector>
#include "base.h"
#include "graph_utils.h"
namespace
sccl
{
namespace
hardware
{
namespace
topology
{
namespace
graph
{
class
Graph
{
public:
Graph
(
int
rank
,
int
nRanks
);
virtual
~
Graph
();
// 通信路径计算
scclResult_t
calculateCommunicationPaths
(
const
BootstrapComm_t
*
bootstrap_comm
);
// 逻辑拓扑构建
scclResult_t
buildLogicalTopology
();
// 根据无向图计算topo路径
scclResult_t
calculateTopoChannels
();
private:
std
::
vector
<
std
::
vector
<
int
>>
adjacencyMatrix
;
// 使用邻接矩阵表示图
// 你可以根据需要添加更多的私有成员变量和函数
};
}
// namespace graph
}
// namespace topology
}
// namespace hardware
}
// namespace sccl
src/hardware/topology/graph/graph_utils.cpp
0 → 100644
View file @
571a75b5
#include <string.h>
#include "graph_utils.h"
namespace
sccl
{
namespace
hardware
{
namespace
topology
{
namespace
graph
{
///
}
// namespace graph
}
// namespace topology
}
// namespace hardware
}
// namespace sccl
src/hardware/topology/graph/graph_utils.h
0 → 100644
View file @
571a75b5
#pragma once
#include <string.h>
#include "bootstrap.h"
#include "graph_utils.h"
namespace
sccl
{
namespace
hardware
{
namespace
topology
{
namespace
graph
{
typedef
bootstrap
::
physical_links
::
scclTopoNode_t
scclTopoNode_t
;
typedef
bootstrap
::
scclNodeInfo_t
scclNodeInfo_t
;
typedef
bootstrap
::
BootstrapComm_t
BootstrapComm_t
;
}
// namespace graph
}
// namespace topology
}
// namespace hardware
}
// namespace sccl
src/hardware/topology/graph/paths.cpp
0 → 100644
View file @
571a75b5
#include <unordered_set>
#include "paths.h"
namespace
sccl
{
namespace
hardware
{
namespace
topology
{
namespace
graph
{
PathFinder
::
PathFinder
(
const
BootstrapComm_t
*
bootstrap_comm
)
:
rank
(
bootstrap_comm
->
rank
),
nRanks
(
bootstrap_comm
->
nRanks
),
localRank
(
bootstrap_comm
->
localRank
),
nLocalRanks
(
bootstrap_comm
->
nLocalRanks
),
interRank
(
bootstrap_comm
->
interRank
),
nInterRanks
(
bootstrap_comm
->
nInterRanks
),
node_container_
(
bootstrap_comm
->
rank_phys_set
->
node_info_vec
.
data
(),
bootstrap_comm
->
nRanks
*
bootstrap_comm
->
rank_phys_set
->
node_info_total_bytes
)
{
// 初始化NodeContainer对象
printf
(
"get PathFinder, node_container_=%zu
\n
"
,
node_container_
.
size
());
for
(
size_t
i
=
0
;
i
<
node_container_
.
size
();
++
i
)
{
scclTopoNode_t
*
node
=
node_container_
[
i
];
// 检查node是否有效
if
(
node
->
type
>
CPU
)
{
// 将有效的node添加到graph_nodes中,并保存其neighbor的id
graph_nodes_
[
node
->
id
]
=
std
::
vector
<
uint64_t
>
(
node
->
neighbors
.
begin
(),
node
->
neighbors
.
begin
()
+
node
->
neighborCount
);
// 构建id到index的映射
id_to_index_
[
node
->
id
]
=
i
;
}
}
#if 0
if(rank == 0) {
// 遍历id_to_index_进行打印
for(const auto& pair : id_to_index_) {
uint64_t node_id = pair.first;
size_t index = pair.second;
const scclTopoNode_t* node = node_container_[index];
int interRank, deviceValue, terminalType, hipDev, numaId;
bootstrap::physical_links::getIdComponents(node_id, &interRank, &deviceValue, &terminalType, &hipDev, &numaId);
char busIdStr[17];
int64ToBusId(node->busId, busIdStr);
printf("rank=%d, node=(InterRank:%d, V:%d, T:%d, H:%d, N:%d, type:%d, busIdStr:%s), neighbor_count=%zu",
rank,
interRank,
deviceValue,
terminalType,
hipDev,
numaId,
node->type,
busIdStr,
node->neighborCount);
for(int n = 0; n < node->neighborCount; ++n) {
uint64_t neighbor_id = node->neighbors[n];
const scclTopoNode_t* neighbor_node = findNodeById(neighbor_id);
if(neighbor_node) {
bootstrap::physical_links::getIdComponents(neighbor_id, &interRank, &deviceValue, &terminalType, &hipDev, &numaId);
int64ToBusId(neighbor_node->busId, busIdStr);
printf(", neighbor[%d]=(InterRank:%d, V:%d, T:%d, H:%d, N:%d, type:%d, busIdStr:%s)",
n,
interRank,
deviceValue,
terminalType,
hipDev,
numaId,
neighbor_node->type,
busIdStr);
} else {
printf(", neighbor[%d]=unknown", n);
}
}
printf("\n");
}
}
#endif
}
scclResult_t
PathFinder
::
findGpuPaths
()
{
// 查找所有type为GPU的节点,并执行BFS搜索
for
(
const
auto
&
pair
:
id_to_index_
)
{
uint64_t
id
=
pair
.
first
;
size_t
index
=
pair
.
second
;
// 定位到node
scclTopoNode_t
*
node
=
node_container_
[
index
];
int
hipDev
;
bootstrap
::
physical_links
::
getIdComponents
(
node
->
id
,
nullptr
,
nullptr
,
nullptr
,
&
hipDev
,
nullptr
);
if
(
node
->
type
==
GPU
&&
hipDev
<
nLocalRanks
)
{
printf
(
"bfsFindGpuPaths start_node_id=%lu, running
\n
"
,
node
->
id
);
bfsFindGpuPaths
(
node
->
id
);
}
}
if
(
rank
==
1
)
{
printGpuPaths
();
}
return
scclSuccess
;
}
/////////////////////////////////////////////////////////////////////////////////////////////
/**
* @brief 根据节点ID查找节点
*
* 该函数接收一个节点ID,并在`node_container_`中查找具有该ID的节点。如果找到了具有指定ID的节点,则返回指向该节点的指针;否则返回`nullptr`。
*
* @param id 要查找的节点ID
* @return 如果找到了具有指定ID的节点,则返回指向该节点的指针;否则返回`nullptr`
*/
const
scclTopoNode_t
*
PathFinder
::
findNodeById
(
uint64_t
id
)
const
{
// 使用id_to_index_映射查找具有指定id的节点的索引
auto
it
=
id_to_index_
.
find
(
id
);
if
(
it
!=
id_to_index_
.
end
())
{
return
node_container_
[
it
->
second
];
}
return
nullptr
;
// 如果未找到具有指定id的节点,则返回nullptr
}
// 为std::vector<uint64_t>类型定义一个相等比较函数
struct
VectorEqual
{
bool
operator
()(
const
std
::
vector
<
uint64_t
>&
lhs
,
const
std
::
vector
<
uint64_t
>&
rhs
)
const
{
if
(
lhs
.
size
()
!=
rhs
.
size
())
{
return
false
;
}
for
(
size_t
i
=
0
;
i
<
lhs
.
size
();
++
i
)
{
if
(
lhs
[
i
]
!=
rhs
[
i
])
{
return
false
;
}
}
return
true
;
}
};
// 为std::vector<uint64_t>类型定义一个哈希函数
struct
VectorHash
{
size_t
operator
()(
const
std
::
vector
<
uint64_t
>&
vec
)
const
{
size_t
seed
=
vec
.
size
();
for
(
const
auto
&
i
:
vec
)
{
seed
^=
i
+
0x9e3779b9
+
(
seed
<<
6
)
+
(
seed
>>
2
);
}
return
seed
;
}
};
/**
* @brief 使用广度优先搜索(BFS)查找从起始GPU节点到其他GPU节点的所有路径
*
* 1.该函数从指定的起始GPU节点开始,使用广度优先搜索算法查找所有能够到达的GPU节点,并记录从起始节点到每个目标GPU节点的所有路径。
* 每条路径中的所有节点最多使用一次。
*
* 2.该函数还添加了一个限制,以防止在路径中出现`interRank`在变化后又变回来的情况。
* 也就是说,如果路径从`interRank == 0`连接到`interRank == 1`的节点后,则不能再连接回`interRank == 0`。
*
* @param start_node_id 起始GPU节点的ID
*/
#if 1
void
PathFinder
::
bfsFindGpuPaths
(
uint64_t
start_node_id
)
{
// 使用一个队列来存储当前路径
std
::
queue
<
std
::
vector
<
uint64_t
>>
queue
;
// 使用一个unordered_map来存储每个node的最短路径
std
::
unordered_map
<
uint64_t
,
std
::
vector
<
uint64_t
>>
shortest_paths
;
// 将起始节点加入队列
queue
.
push
({
start_node_id
});
shortest_paths
[
start_node_id
]
=
{
start_node_id
};
// 当队列不为空时,继续搜索
while
(
!
queue
.
empty
())
{
// 从队列中取出一个路径
auto
path
=
queue
.
front
();
queue
.
pop
();
// 获取当前路径的最后一个节点的ID
uint64_t
nodeId
=
path
.
back
();
// 根据节点ID查找对应的节点
const
scclTopoNode_t
*
current_node
=
findNodeById
(
nodeId
);
if
(
current_node
==
nullptr
)
{
continue
;
}
// 如果当前节点是GPU节点且不是起始节点,则将当前路径加入结果
if
(
current_node
->
type
==
GPU
&&
nodeId
!=
start_node_id
)
{
int
hipDev
;
bootstrap
::
physical_links
::
getIdComponents
(
current_node
->
id
,
nullptr
,
nullptr
,
nullptr
,
&
hipDev
,
nullptr
);
if
(
hipDev
<
nLocalRanks
)
{
gpu_paths_
[
start_node_id
].
push_back
(
path
);
}
}
else
{
int
nodeInterRank
;
bootstrap
::
physical_links
::
getIdComponents
(
nodeId
,
&
nodeInterRank
);
// 遍历当前节点的所有邻居节点
for
(
uint64_t
neighbor_id
:
graph_nodes_
.
at
(
nodeId
))
{
if
(
findNodeById
(
neighbor_id
)
==
nullptr
)
{
continue
;
}
// 获取邻居节点的interRank
int
neighbor_inter_rank
;
bootstrap
::
physical_links
::
getIdComponents
(
neighbor_id
,
&
neighbor_inter_rank
);
// 检查邻居节点是否已在当前路径中访问过
bool
visited
=
std
::
find
(
path
.
begin
(),
path
.
end
(),
neighbor_id
)
!=
path
.
end
();
// 检查interRank是否已经存在(仅当interRank改变时)
bool
inter_rank_exists
=
false
;
if
(
neighbor_inter_rank
!=
nodeInterRank
)
{
for
(
uint64_t
node_id
:
path
)
{
if
(
node_id
==
neighbor_id
)
{
inter_rank_exists
=
true
;
break
;
}
}
}
// 如果邻居节点未访问过且interRank未存在,则扩展路径
if
(
!
visited
&&
!
inter_rank_exists
)
{
std
::
vector
<
uint64_t
>
new_path
=
path
;
new_path
.
push_back
(
neighbor_id
);
// 如果新路径比已有的最短路径更短,则更新最短路径
if
(
shortest_paths
.
find
(
neighbor_id
)
==
shortest_paths
.
end
()
||
shortest_paths
[
neighbor_id
].
size
()
>
new_path
.
size
())
{
shortest_paths
[
neighbor_id
]
=
new_path
;
queue
.
push
(
new_path
);
}
}
}
}
}
}
#else
void
PathFinder
::
bfsFindGpuPaths
(
uint64_t
start_node_id
)
{
// 使用一个队列来存储当前路径
std
::
queue
<
std
::
vector
<
uint64_t
>>
queue
;
// 将起始节点加入队列
queue
.
push
({
start_node_id
});
// 当队列不为空时,继续搜索
while
(
!
queue
.
empty
())
{
// 从队列中取出一个路径
auto
path
=
queue
.
front
();
queue
.
pop
();
// 获取当前路径的最后一个节点的ID
uint64_t
nodeId
=
path
.
back
();
// 根据节点ID查找对应的节点
const
scclTopoNode_t
*
current_node
=
findNodeById
(
nodeId
);
if
(
current_node
==
nullptr
)
{
continue
;
}
// 如果当前节点是GPU节点且不是起始节点,则将当前路径加入结果
if
(
current_node
->
type
==
GPU
&&
nodeId
!=
start_node_id
)
{
int
hipDev
;
bootstrap
::
physical_links
::
getIdComponents
(
current_node
->
id
,
nullptr
,
nullptr
,
nullptr
,
&
hipDev
,
nullptr
);
if
(
hipDev
<
nLocalRanks
)
{
gpu_paths_
[
start_node_id
].
push_back
(
path
);
}
}
else
{
int
nodeInterRank
;
bootstrap
::
physical_links
::
getIdComponents
(
nodeId
,
&
nodeInterRank
);
// 遍历当前节点的所有邻居节点
for
(
uint64_t
neighbor_id
:
graph_nodes_
.
at
(
nodeId
))
{
if
(
findNodeById
(
nodeId
)
==
nullptr
)
{
continue
;
}
// 获取邻居节点的interRank
int
neighbor_inter_rank
;
bootstrap
::
physical_links
::
getIdComponents
(
neighbor_id
,
&
neighbor_inter_rank
);
// 检查邻居节点是否已在当前路径中访问过
bool
visited
=
std
::
find
(
path
.
begin
(),
path
.
end
(),
neighbor_id
)
!=
path
.
end
();
// 检查interRank是否已经存在(仅当interRank改变时)
bool
inter_rank_exists
=
false
;
if
(
neighbor_inter_rank
!=
(
nodeInterRank
))
{
for
(
uint64_t
node_id
:
path
)
{
if
((
nodeInterRank
)
==
neighbor_inter_rank
)
{
inter_rank_exists
=
true
;
break
;
}
}
}
// 如果邻居节点未访问过且interRank未存在,则扩展路径
if
(
!
visited
&&
!
inter_rank_exists
)
{
std
::
vector
<
uint64_t
>
new_path
=
path
;
new_path
.
push_back
(
neighbor_id
);
queue
.
push
(
new_path
);
}
}
}
}
}
#endif
/**
* @brief 打印GPU路径信息
*
* 该函数用于打印`gpu_paths_`中存储的所有GPU路径信息。对于每一条路径,
* 它会打印路径的长度以及路径中每个节点的详细信息,包括节点的`interRank`、
* `deviceValue`、`terminalType`和`numaId`。
*/
void
PathFinder
::
printGpuPaths
()
{
// 遍历gpu_paths_中的每一对(start_node_id, paths)
for
(
const
auto
&
start_node_pair
:
gpu_paths_
)
{
uint64_t
start_node_id
=
start_node_pair
.
first
;
// 获取起始节点的ID
char
busIdStr
[
17
]
=
""
;
// 用于存储总线ID字符串
// 根据起始节点的ID查找对应的节点对象
const
scclTopoNode_t
*
start_node
=
findNodeById
(
start_node_id
);
// 如果找到了对应的节点对象,则将其总线ID转换为字符串
if
(
start_node
)
{
int64ToBusId
(
start_node
->
busId
,
busIdStr
);
}
else
{
return
;
}
const
auto
&
paths
=
start_node_pair
.
second
;
// 获取与起始节点关联的所有路径
size_t
path_count
=
paths
.
size
();
// 计算路径的数量
int
interRank
,
deviceValue
,
terminalType
,
hipDev
,
numaId
;
// 根据起始节点的ID获取其interRank、deviceValue、terminalType和numaId
bootstrap
::
physical_links
::
getIdComponents
(
start_node_id
,
&
interRank
,
&
deviceValue
,
&
terminalType
,
&
hipDev
,
&
numaId
);
printf
(
"GPU node ID:%lu (InterRank:%d, V:%d, T:%d, H:%d, N:%d) (Path count: %zu)
\n
"
,
start_node_id
,
interRank
,
deviceValue
,
terminalType
,
hipDev
,
numaId
,
path_count
);
// 遍历与起始节点关联的所有路径
for
(
const
auto
&
path
:
paths
)
{
size_t
path_length
=
path
.
size
();
// 计算路径的长度
// 打印路径的长度
printf
(
"Path (length: %zu): "
,
path_length
);
// 遍历路径中的每个节点
for
(
size_t
i
=
0
;
i
<
path
.
size
();
++
i
)
{
uint64_t
node_id
=
path
[
i
];
// 获取节点的ID
// 使用findNodeById函数查找节点的详细信息
const
scclTopoNode_t
*
node
=
findNodeById
(
node_id
);
if
(
node
)
{
// 根据节点的ID获取其interRank、deviceValue、terminalType和numaId
bootstrap
::
physical_links
::
getIdComponents
(
node
->
id
,
&
interRank
,
&
deviceValue
,
&
terminalType
,
&
hipDev
,
&
numaId
);
// 将节点的总线ID转换为字符串
int64ToBusId
(
node
->
busId
,
busIdStr
);
// 打印节点的信息,包括其interRank、deviceValue、terminalType、numaId、类型和总线ID字符串
printf
(
"ID:%lu (InterRank:%d, V:%d, T:%d, H:%d, N:%d, type:%d, busIdStr:%s)"
,
node
->
id
,
interRank
,
deviceValue
,
terminalType
,
hipDev
,
numaId
,
node
->
type
,
busIdStr
);
}
// 如果当前节点不是路径中的最后一个节点,则打印" -> "以分隔节点
if
(
i
!=
path
.
size
()
-
1
)
{
printf
(
" -> "
);
}
}
// 换行,准备打印下一条路径
printf
(
"
\n
=============================================
\n
"
);
}
}
}
}
// namespace graph
}
// namespace topology
}
// namespace hardware
}
// namespace sccl
src/hardware/topology/graph/paths.h
0 → 100644
View file @
571a75b5
#pragma once
#include <vector>
#include <queue>
#include <unordered_map>
#include <cstring> // 为了使用strlen
#include "base.h"
#include "graph_utils.h"
namespace
sccl
{
namespace
hardware
{
namespace
topology
{
namespace
graph
{
class
PathFinder
{
public:
// 构造函数
PathFinder
(
const
BootstrapComm_t
*
bootstrap_comm
);
// 打印函数
scclResult_t
findGpuPaths
();
// 打印函数
void
printGpuPaths
();
private:
ByteSpanArray
<
scclTopoNode_t
>
node_container_
;
// 使用NodeContainer来存储nodes数据
std
::
unordered_map
<
uint64_t
,
std
::
vector
<
uint64_t
>>
graph_nodes_
;
// 使用无序映射存储图的节点和它们的邻居
std
::
unordered_map
<
uint64_t
,
std
::
vector
<
std
::
vector
<
uint64_t
>>>
gpu_paths_
;
// 使用无序映射存储从每个GPU节点到其他GPU节点的所有路径
// 存储node.id到nodes_span索引的映射
std
::
unordered_map
<
uint64_t
,
size_t
>
id_to_index_
;
// 使用广度优先搜索(BFS)查找从起始GPU节点到其他GPU节点的所有路径
void
bfsFindGpuPaths
(
uint64_t
start_node_id
);
// 根据node.id查找节点的函数
const
scclTopoNode_t
*
findNodeById
(
uint64_t
id
)
const
;
int
rank
=
-
1
;
// 当前节点的全局排名
int
nRanks
=
0
;
// 总的节点数量
int
localRank
=
-
1
;
// 当前节点在本地计算节点中的排名
int
nLocalRanks
=
0
;
// 本地计算节点中的节点总数
int
interRank
=
-
1
;
// 整个节点在全部节点中的位置
int
nInterRanks
=
0
;
// 全局拥有节点的个数
};
}
// namespace graph
}
// namespace topology
}
// namespace hardware
}
// namespace sccl
src/hardware/topology/graph/readme.MD
0 → 100644
View file @
571a75b5
## 用于构建拓扑图
包括3个部分:
-
物理拓扑构建:CPU、GPU、PCIe、NVLink等物理连接
-
通信路径计算:GPU到其他GPU的连接通信路径(生成无向图)
-
逻辑拓扑构建:生成各种形状的逻辑拓扑,如ring、tree、mesh、等
其中,物理拓扑构建表示硬件节点间的连接,已经在bootstrap文件夹中完成
本文件完成通信路径计算和逻辑拓扑构建
按照文件夹内功能分类如下:
hardware_topo:
-
通信路径计算
logical_topo:
-
逻辑拓扑构建
-
根据无向图计算topo路径
src/hardware/topology/topo_utils.cpp
View file @
571a75b5
...
...
@@ -5,11 +5,28 @@ namespace sccl {
namespace
hardware
{
namespace
topology
{
/**
* 将64位整数转换为PCI总线ID字符串
*
* @param id 输入的64位整数,包含PCI总线ID信息
* @param busId 输出缓冲区,用于存储格式化后的PCI总线ID字符串(格式为"域:总线:设备.功能")
* @return 返回scclSuccess表示成功
*/
scclResult_t
int64ToBusId
(
int64_t
id
,
char
*
busId
)
{
sprintf
(
busId
,
"%04lx:%02lx:%02lx.%01lx"
,
(
id
)
>>
20
,
(
id
&
0xff000
)
>>
12
,
(
id
&
0xff0
)
>>
4
,
(
id
&
0xf
));
return
scclSuccess
;
}
/**
* 将总线ID字符串转换为64位整数值
*
* @param busId 输入的总线ID字符串,可能包含分隔符(.或:)
* @param id 输出参数,用于存储转换后的64位整数值
* @return 返回操作结果,scclSuccess表示成功
*
* @note 总线ID字符串中的非十六进制字符(0-9,a-f,A-F)和分隔符将被忽略
* 转换后的值通过strtol以16进制解析获得
*/
scclResult_t
busIdToInt64
(
const
char
*
busId
,
int64_t
*
id
)
{
char
hexStr
[
17
];
// Longest possible int64 hex string + null terminator.
int
hexOffset
=
0
;
...
...
@@ -27,6 +44,40 @@ scclResult_t busIdToInt64(const char* busId, int64_t* id) {
return
scclSuccess
;
}
#define BUSID_SIZE (sizeof("0000:00:00.0"))
#define BUSID_REDUCED_SIZE (sizeof("0000:00"))
static
void
memcpylower
(
char
*
dst
,
const
char
*
src
,
const
size_t
size
)
{
for
(
int
i
=
0
;
i
<
size
;
i
++
)
dst
[
i
]
=
tolower
(
src
[
i
]);
}
/**
* @brief 获取给定PCI设备的路径。
*
* 此函数根据提供的PCI设备的总线ID(busId),生成该设备在系统中的实际路径。
* 它首先构造一个可能的路径字符串,然后使用`realpath`函数将其转换为实际的文件系统路径。
* 如果路径无法解析,函数将返回一个错误代码。
*
* @param busId 一个C字符串,表示PCI设备的总线ID。例如:"0000:00:00.0"。
* @param path 一个指向字符指针的指针,用于存储解析后的实际路径。调用者负责释放此内存。
*
* @return scclResult_t 返回操作结果。如果成功,返回`scclSuccess`;如果失败,返回`scclSystemError`。
*
* @note 此函数内部使用了`realpath`函数,该函数可能因路径不存在或其他系统错误而失败。
* 在这种情况下,函数将输出一个警告信息,并返回错误代码。
*/
scclResult_t
getPciPath
(
const
char
*
busId
,
char
**
path
)
{
char
busPath
[]
=
"/sys/class/pci_bus/0000:00/../../0000:00:00.0"
;
memcpylower
(
busPath
+
sizeof
(
"/sys/class/pci_bus/"
)
-
1
,
busId
,
BUSID_REDUCED_SIZE
-
1
);
memcpylower
(
busPath
+
sizeof
(
"/sys/class/pci_bus/0000:00/../../"
)
-
1
,
busId
,
BUSID_SIZE
-
1
);
*
path
=
realpath
(
busPath
,
NULL
);
if
(
*
path
==
NULL
)
{
WARN
(
"Could not find real path of %s"
,
busPath
);
return
scclSystemError
;
}
return
scclSuccess
;
}
// 定义一个常量,表示最大字符串长度
static
constexpr
int
MAX_STR_LEN
=
255
;
...
...
src/hardware/topology/topo_utils.h
View file @
571a75b5
#pragma once
#include <string.h>
#include <map>
#include <string>
#include <cstddef>
#include "base.h"
#include "net.h"
#include "hardware_utils.h"
...
...
@@ -9,9 +11,18 @@ namespace sccl {
namespace
hardware
{
namespace
topology
{
#define SCCL_TOPO_NODE_TYPES (6) // 硬件node的类型
#define SCCL_TOPO_MAX_NODE_PER_TYPE (4) // 每个硬件node类型中节点的数量,间接表明网络拓扑结构的最大层数
#define SCCL_TOPO_RANK_MAX_LINKS (8) // 每个rank中节点与当前rank中其他节点的链接数量
constexpr
int
SCCL_TOPO_NODE_TYPES
=
6
;
// 硬件node的类型数量
constexpr
int
SCCL_TOPO_MAX_NODE_PER_TYPE
=
4
;
// 每个硬件node类型中节点的数量,间接表明网络拓扑结构的最大层数
constexpr
int
SCCL_TOPO_RANK_MAX_LINKS
=
8
;
// 每个rank中节点与当前rank中其他节点的链接数量
typedef
enum
:
int
{
CPU
=
1
,
// 实际是numa域
PCI
=
2
,
GPU
=
3
,
NVS
=
4
,
// 包括XGMI和NVLink
NIC
=
5
,
NET
=
6
// 主要是RDMA网卡
}
nodeType_t
;
// 定义 topoPathType_t 枚举类型,用于表示不同的路径类型。
enum
topoPathType
{
...
...
@@ -58,6 +69,8 @@ scclResult_t int64ToBusId(int64_t id, char* busId);
// 将总线ID字符串转换为64位整数
scclResult_t
busIdToInt64
(
const
char
*
busId
,
int64_t
*
id
);
scclResult_t
getPciPath
(
const
char
*
busId
,
char
**
path
);
// 将PCI路径转换为64位整数,路径偏移量和最小偏移量作为参数
scclResult_t
pciPathToInt64
(
char
*
path
,
int
offset
,
int
minOffset
,
int64_t
*
id
);
...
...
src/include/base.h
View file @
571a75b5
...
...
@@ -8,6 +8,7 @@
#include "alloc.h"
#include "utils.h"
#include "asm_ops.h"
#include "container.h"
/*
外部环境变量设置:
...
...
src/include/check.h
View file @
571a75b5
...
...
@@ -74,13 +74,13 @@ static const char* scclGetErrorString(scclResult_t code) {
} \
} while(0);
#define SCCLCHECKGOTO(call, RES, label) \
do { \
RES = call; \
if(RES != scclSuccess && RES != scclInProgress) { \
INFO(SCCL_LOG_CODEALL, "%s:%d -> %d", __func__, __
FIL
E__, __
LIN
E__, RES); \
goto label; \
} \
#define SCCLCHECKGOTO(call, RES, label)
\
do {
\
RES = call;
\
if(RES != scclSuccess && RES != scclInProgress) {
\
INFO(SCCL_LOG_CODEALL, "%s:%d
%s
-> %d", __func__, __
LIN
E__, __
FIL
E__, RES); \
goto label;
\
}
\
} while(0);
#define HIPCHECK(cmd) \
...
...
Prev
1
2
3
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment