前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >DAOS分布式存储_libfabric_高性能RPC_rdma网络_笔记

DAOS分布式存储_libfabric_高性能RPC_rdma网络_笔记

原创
作者头像
晓兵
发布2023-11-03 21:52:07
4200
发布2023-11-03 21:52:07
举报
文章被收录于专栏:daosdaos
代码语言:javascript
复制
https://github.com/ssbandjl/libfabric.git
git remote add upstream https://github.com/ofiwg/libfabric.git
git fetch upstream
git merge upstream/main

订阅: https://www.openfabrics.org/subscriptions-at-ofa/
归档的历史讨论: https://lists.openfabrics.org/pipermail/ofiwg/
程序员手册: https://ofiwg.github.io/libfabric/
开发指南手册: https://github.com/ofiwg/ofi-guide/blob/master/OFIGuide.md
设计要点:
允许立即重用数据缓冲区, send() 将应用程序的数据复制到内部缓冲区中。然后从该缓冲区发出数据传输,这允许在失败的情况下重试操作。在这种情况下,send() 调用不会被阻塞,但是所有通过网络的数据都会导致内存复制到本地缓冲区,即使没有任何错误, 为了避免发送方的内存复制,我们需要将应用程序数据直接放到网络上。如果我们还想避免阻塞发送应用程序,我们需要一些方法让网络层在缓冲区可以安全重用时与应用程序通信。这将允许在需要重新传输数据的情况下重新使用缓冲区。这导致我们设计了一个异步行为的网络接口。应用程序需要发出请求,然后在请求完成时收到某种通知

Libfabric 将等待对象与队列分开

fi_trywait 实现负责处理可能导致应用程序丢失事件或挂起的潜在竞争条件




https://ofiwg.github.io/libfabric/v1.10.1/man/fabtests.7.html
fabtests 测试, fabtests/README, fabtests/README.md
使用 --with-libfabric=<directory> 选项告诉 Fabtests 在哪里可以找到已安装的 Libfabric 的头文件和库文件
编译:
./autogen.sh
./configure --with-libfabric=/opt/libfabric --prefix=/opt/fabtests && make -j 32 && sudo make install   #or
./configure --prefix=/opt/fabtests && make -j 32 && sudo make install
./configure --with-libfabric=/home/xb/project/net/libfabric/libfabric/build/libfabric --prefix=/home/xb/project/net/libfabric/libfabric/build/fabtests --enable-debug && make -j 32 && sudo make install

server
#原生网卡名
fi_pingpong -e rdm -p "verbs;ofi_rxm" -m tagged -d mlx5_0 -v -I 2

client
fi_pingpong -e rdm -p "verbs;ofi_rxm" -m tagged 175.16.53.73 -v -I 2

server
gdb --args ./build/fabtests/bin/fi_pingpong -e rdm -p "verbs;ofi_rxm" -m tagged -d mlx5_0 -v -I 2
fi_pingpong源码: util/pingpong.c
main -> int main(int argc, char **argv)
ct.hints = fi_allocinfo()
ct.hints->ep_attr->type = FI_EP_DGRAM 数据报端点
ofi_osd_init -> null
getopt -> static void pp_parse_opts 解析参数
  case 'e' Endpoint -> ct->hints->ep_attr->type = FI_EP_RDM
  case 'p' Provider -> ct->hints->fabric_attr->prov_name = strdup(optarg) verbs;ofi_rxm
  case 'm' ct->hints->caps &= ~FI_MSG -> ct->hints->caps |= FI_TAGGED 去掉和增加标记
  case 'd' Domain -> ct->hints->domain_attr->name = strdup(optarg)
  case 'I' Iterations 迭代/重复 -> ct->opts.options |= PP_OPT_ITER
ct.opts.dst_addr -> 
pp_banner_options -> static void pp_banner_options 打印横幅banner
  opts.transfer_size 64
  PP_DEBUG(" * PingPong options:\n")
switch (ct.hints->ep_attr->type) -> case FI_EP_RDM -> ret = run_pingpong_rdm(&ct) -> static int run_pingpong_rdm
  pp_init_fabric -> static int pp_init_fabric
    pp_ctrl_init -> static int pp_ctrl_init
      default_ctrl = 47592 默认服务端口
      pp_ctrl_init_server -> static int pp_ctrl_init_server
        listenfd = ofi_socket(pp_ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0) -> static inline SOCKET ofi_socket(int domain, int type, int protocol) -> socket(domain, type, protocol)
        setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR
        struct sockaddr_in ctrl_addr = {0}
        ctrl_addr.sin_port = htons(ct->opts.src_port) 47592
        ctrl_addr.sin_addr.s_addr = htonl(INADDR_ANY)
        ret = bind(listenfd
        listen(listenfd, 10)
        ct->ctrl_connfd = accept(listenfd, NULL, NULL) 等待客户端调用connect触发服务端accept
        ofi_close_socket(listenfd)
      setsockopt(ct->ctrl_connfd
  run_suite_pingpong
  pp_finalize
pp_free_res


client:
gdb --args ./build/fabtests/bin/fi_pingpong -e rdm -p "verbs;ofi_rxm" -m tagged 175.16.53.73 -v -I 2
ct.hints = fi_allocinfo
ct.opts.dst_addr 175.16.53.73
run_pingpong_rdm -> static int run_pingpong_rdm
pp_init_fabric -> pp_ctrl_init_client
  connect(ct->ctrl_connfd, rp->ai_addr, (socklen_t) rp->ai_addrlen) 连接服务端, 服务端执行accept
setsockopt(ct->ctrl_connfd
pp_ctrl_init
if (ct->opts.dst_addr)
pp_recv_name
pp_getinfo
pp_open_fabric_res
pp_alloc_active_res
pp_init_ep
pp_send_name
pp_av_insert

run_suite_pingpong
pp_finalize

编译:
make util/fi_pingpong -> util/fi_pingpong$(EXEEXT)

端点类型:
enum fi_ep_type {
	FI_EP_UNSPEC,
	FI_EP_MSG,
	FI_EP_DGRAM,
	FI_EP_RDM,
	FI_EP_SOCK_STREAM,
	FI_EP_SOCK_DGRAM,
};



宏
int DEFAULT_SYMVER_PRE(fi_getinfo)



dos2unix autogen.sh
./autogen.sh
./configure --prefix="" --disable-efa --disable-psm3 --without-gdrcopy --enable-debug --disable-psm2 --disable-psm3
make && make install


fi_pingpong -p sockets
fi_pingpong -p sockets "localhost" -v

server:
fi_pingpong -p sockets


makeword是将两个byte型合并成一个word型,一个在高8位(b),一个在低8位(a)
MAKEWORD(2,2)就是调用2.2版

client:
fi_pingpong -p sockets "192.168.1.6" -v

export PATH=/root/github/storage/daos/libfabric/util:/home/xb/project/libfabric/libfabric/build/fabtests/bin:$PATH
s63: export PATH=/home/xb/project/libfabric/libfabric/build/fabtests/bin:$PATH
util/pingpong.c

server:
main -> ofi_osd_init -> MAKEWORD -> WSAStartup -> pp_parse_opts 解析参数 -> pp_banner_options 打印横幅 -> FI_EP_RDM -> run_pingpong_rdm -> pp_init_fabric -> run_suite_pingpong -> pp_finalize

pp_init_fabric -> 

client:

run_pingpong_rdm -> PP_POST -> 

fi_pingpong.1.md

WRITE:写
vrb_msg_ep_rma_write -> IBV_WR_RDMA_WRITE -> ibv_post_send

debug:
FI_WARN(&core_prov, FI_LOG_CORE, "iov:%p\n", iov);


tcpx_tx_queue_insert -> 

fi_tsend -> rxm_ep_tsend -> rxm_get_conn -> rxm_send_common -> rxm_send_eager -> rxm_msg_tsend -> tcpx_tx_queue_insert -> rxm_cq_write 发完后写完成队列 -> ofi_cq_write


断点: rxm_ep_tsend

获取连接:
rxm_get_conn
  ofi_av_addr_context
    ofi_av_get_addr
      ofi_bufpool_get_ibuf
  rxm_add_conn
    ofi_idm_lookup
    rxm_alloc_conn
      rxm_av_alloc_conn
        ofi_buf_alloc(av->conn_pool)
          ofi_bufpool_grow
  rxm_ep_do_progress
  rxm_connect
    rxm_send_connect 空闲状态则建立连接(RXM_CM_IDLE)
      rxm_open_conn
        fi_endpoint
        fi_ep_bind
        fi_enable
        rxm_prepost_recv
      rxm_init_connect_data 将被动端点做连接请求发送到服务器
      fi_connect
        tcpx_ep_connect
          ofi_wait_add_fd epoll
  rxm_conn_progress
    fi_eq_read 循环读取,从事件队列读取事件
    rxm_handle_event
    rxm_handle_error


rxm_ep_do_progress
  do
    fi_cq_read
    handle_comp_error rxm_handle_comp_error
      fi_cq_readerr
      ofi_cq_write_error



1. fi_tsend
/lib/libfabric.so.1(+0xf8b83) [0x7fbe1c660b83]
/root/github/storage/daos/mercury/build/bin/libna.so.2(+0xf494) [0x7fbe1c744494]
/root/github/storage/daos/mercury/build/bin/libna.so.2(+0xf875) [0x7fbe1c744875]
/root/github/storage/daos/mercury/build/bin/libmercury.so.2(+0xee1a) [0x7fbe1c99fe1a]
/root/github/storage/daos/mercury/build/bin/libmercury.so.2(HG_Core_forward+0x140) [0x7fbe1c9a8550]
/root/github/storage/daos/mercury/build/bin/libmercury.so.2(HG_Forward+0xc8) [0x7fbe1c999f98]
2.  na_ofi_progress
/root/github/storage/daos/mercury/build/bin/libna.so.2(+0x139ac) [0x7fbe1c7489ac]
/root/github/storage/daos/mercury/build/bin/libna.so.2(NA_Progress+0x24b) [0x7fbe1c73d77b]
/root/github/storage/daos/mercury/build/bin/libmercury.so.2(+0xffbb) [0x7fbe1c9a0fbb]
/root/github/storage/daos/mercury/build/bin/libmercury.so.2(+0x12169) [0x7fbe1c9a3169]
/root/github/storage/daos/mercury/build/bin/libmercury.so.2(HG_Core_progress+0x10) [0x7fbe1c9a8920]
/root/github/storage/daos/mercury/build/bin/libmercury.so.2(HG_Progress+0x18) [0x7fbe1c99a378]


recv_list


HG_Progress
  NA_Progress
    na_ofi_progress
      ofi_cq_readfrom -> ofi_cq_progress -> rxm_ep_progress -> rxm_ep_do_progress -> rxm_handle_comp ->     rxm_finish_eager_send -> rxm_cq_write_tx_comp -> rxm_cq_write -> print_stacktrace  -> HG -> na_ofi_cq_read
      ssize_t ofi_cq_readfrom(struct fid_cq *cq_fid, void *buf, size_t count, fi_addr_t *src_addr)  
        cq->progress(cq) -> void ofi_cq_progress(struct util_cq *cq) -> fi_cq_read -> vrb_flush_cq
          ibv_poll_cq -> cq转eq -> vrb_eq_read_event
      return ofi_cq_read_entries(cq, buf, count, src_addr)
server: NA_CB_RECV_UNEXPECTED CQ event 非预期接收


地址向量:

ip_av_insert_addr

打印地址
ofi_straddr_dbg(av->prov, FI_LOG_AV, "av_insert addr", addr)

HASH_ADD(hh, av->hash, data, av->addrlen, entry)

ofi_av_write_event

fi_eq_write






fi_cq_open
cq_open vrb_cq_open
ibv_create_cq



2013
获取大页: 
ofi_hugepage_enabled
  ofi_get_hugepage_size
  ofi_alloc_hugepage_buf
  ofi_unmap_anon_pages

check fork: ibv_is_fork_initialized

注册内存:
参考daos: C:\Users\s30893\project\stor\storage\daos\daos.drawio
...
na_ofi_initialize
  na_ofi_class->send_pool = hg_mem_pool_create(pool_chunk_size ... na_ofi_mem_buf_register 注册初始内存池
  na_ofi_class->recv_pool = hg_mem_pool_create -> hg_mem_pool_create(size_t chunk_size
    struct hg_mem_pool_block *hg_mem_pool_block = hg_mem_pool_block_alloc register_func
      int rc = register_func(mem_ptr, block_size, flags, &mr_handle, arg) -> na_ofi_mem_buf_register -> na_ofi_mem_buf_register(const void *buf
        rc = fi_mr_reg(na_ofi_class->domain->fi_domain, buf, len, access,
          .reg = vrb_mr_reg -> vrb_mr_reg(struct fid *fid, const void *buf, size_t len, uint64_t access -> vrb_mr_reg_iface
          _domain->cache.add_region = vrb_mr_cache_add_region; -> int vrb_mr_reg_common -> md->mr = ibv_reg_mr(md->domain->pd, (void *) buf, len,
          

  


立即数: wr.imm_data = htonl((uint32_t)data)



rdma write, 单边写, 写bulk, 写消息
NA_Put
na_ofi_put
na_ofi_rma fi_writemsg = fi_rma_op   .writemsg =    -> include/rdma/fi_rma.h -> fi_writemsg(struct fid_ep *ep, const struct fi_msg_rma *msg, uint64_t flags)
ep->rma->writemsg(ep, msg, flags)
.writemsg = vrb_msg_ep_rma_writemsg
vrb_msg_ep_rma_writemsg -> prov/verbs/src/verbs_rma.c
  struct ibv_send_wr wr
  wr.opcode = IBV_WR_RDMA_WRITE | wr.opcode = IBV_WR_RDMA_WRITE_WITH_IMM 写|立即数写
  vrb_send_iov(ep, &wr, msg->msg_iov, msg->desc -> ssize_t vrb_send_iov
    wr->sg_list = alloca(sizeof(*wr->sg_list) * count)
    wr->sg_list[i].addr = (uintptr_t) iov[i].iov_base
    wr->sg_list[i].length = iov[i].iov_len;
    wr->send_flags = IBV_SEND_INLINE ?IBV_SEND_FENCE
    wr->sg_list[0]
    wr->num_sge =
    vrb_post_send(ep, wr, flags) -> prov/verbs/src/verbs_ep.c -> ssize_t vrb_post_send
      ibv_post_send(ep->ibv_qp, wr, &bad_wr)

所有标签(Flags), include/rdma/fabric.h -> #define FI_MSG			(1ULL << 1) ...



iodepth:
static int vrb_ep_enable
vrb_msg_ep_get_qp_attr(ep, &attr);
  attr->cap.max_send_wr = ep->info_attr.tx_size;
  attr->cap.max_send_sge = ep->info_attr.tx_iov_limit;
  attr->cap.max_recv_wr = ep->info_attr.rx_size;
  attr->cap.max_recv_sge = ep->info_attr.rx_iov_limit;
vrb_create_dgram_ep
  ibv_create_qp


测试安装成功: fi_info


git: https://github.com/ssbandjl/libfabric.git
example: https://github.com/ssbandjl/HOTI_Tutorial_Examples.git


宏
int DEFAULT_SYMVER_PRE(fi_getinfo)

int DEFAULT_SYMVER_PRE(fi_fabric)


fabric.c -> __attribute__ -> int DEFAULT_SYMVER_PRE(fi_fabric) ->


AC_DEFINE_UNQUOTED([ENABLE_DEBUG],[$dbg],
                   [defined to 1 if libfabric was configured with --enable-debug, 0 otherwise])
#if ENABLE_DEBUG


int DEFAULT_SYMVER_PRE(fi_log_enabled)
fi_log


LOGGING INTERFACE


FI_LOG_LEVEL=Debug
FFI_LOG_PROV="verbs"
FI_LOG_SUBSYS="fabric"

env
fi_info -e


fi_endpoint
Fabric endpoint operations


registering provider


RD和UC类型,以及XRC(Extended Reliable Connection)扩展可信连接,SRD(Scalable Reliable Datagram)等更复杂的服务类型



./autogen.sh
autoreconf -ivf
./configure --disable-efa --disable-psm3 --without-gdrcopy --enable-debug --disable-psm2 --disable-psm3
make -j 1
make install


libdir
prefix = /usr
-rpath


server:
fi_listen -> .listen = vrb_pep_listen -> vrb_pep_listen -> rdma_listen


fi_eq_read -> .read = vrb_eq_read -> vrb_eq_read -> vrb_eq_cm_process_event -> RDMA_CM_EVENT_CONNECT_REQUEST




RDMA_CM_EVENT_ADDR_RESOLVED


RDMA_CM_EVENT_ROUTE_RESOLVED


ofi_epoll_wait
client: fi_eq_sread fi_cq_sread
.sread = vrb_eq_sread -> vrb_eq_sread -> vrb_eq_read -> vrb_eq_cm_process_event -> rdma_connect
epoll_wait

fi_fabric -> .fabric = rxm_fabric | vrb_fabric -> int ofi_fabric_init -> 

vrb_fabric -> ofi_fabric_init 


fi_tsend
  rxm_tsend
    

fi_eq_open
  vrb_eq_open
    rdma_create_event_channel



fi_endpoint
  vrb_open_ep
    vrb_create_ep(ep, vrb_get_port_space(info->addr_format), &ep->id)
      rdma_create_id(NULL, id, NULL, ps))


fi_eq_read
  vrb_eq_read
    rdma_get_cm_event
    vrb_eq_cm_process_event 处理事件


fi_connect
  vrb_msg_ep_connect
    rdma_resolve_route


最大发送工作请求数:
info->tx_attr->size, max_send_wr, 


test: fabtests
fabtests/component/dmabuf-rdma/fi-rdmabw-xe.c


test:
HOTI_Tutorial_Examples/2023/example_msg.c -> main
hints = fi_allocinfo()



向客户端-服务器测试引入完成方法,允许客户端-服务器测试更改在检查完成时调用的调用。 当前的方法是旋转 fi_cq_read 直到找到正确的完成次数。 添加一个新方法来支持调用 fi_cq_sread。 后续补丁中可能会出现其他方法
fabtests完成类型:
enum ft_comp_method {
	FT_COMP_SPIN = 0,
	FT_COMP_SREAD, // 同步读
	FT_COMP_WAITSET,
	FT_COMP_WAIT_FD, // 添加轮询 fd 等待对象的完成方法,某些应用程序(例如 rsockets、ES-API)依赖于在与完成队列关联的底层 fd 上调用 poll/select 的能力。 添加新的完成机制来测试提供者是否正确支持这一点。 这也显示了如何进行 fd 处理,以确保与 fd 相关的信号在收到信号后正确重置
	FT_COMP_YIELD,
};



header:
远程内存访问: include/rdma/fi_rma.h
文档: man/fi_rma.3.md
fi_rma_bw, 带宽测试

def test_rma_bw
fabtests/common:添加 HMEM 选项解析支持,此提交负责为 ubertest 添加 HMEM 选项支持。 创建了一个单独的函数 ft_parse_hmem_opts() 将 HMEM 选项与其他选项分开,以便于处理
server: fi_rma_bw -e msg -o write -I 5
client: fi_rma_bw -e msg -o write -I 5 any_ip

推荐端点类型选择连接更少的可靠数据报类型
server: fi_rma_bw -e rdm -o write -I 5 -p verbs
client: fi_rma_bw -e rdm -o write -I 5 -p verbs 172.17.29.63

gdb --args ./fi_rma_bw -e rdm -o write -I 5 -p verbs
server: fabtests/benchmarks/rma_bw.c -> main
opts.options |= FT_OPT_BW
fi_allocinfo
hints->ep_attr->type = FI_EP_RDM
hints->domain_attr->mr_mode = opts.mr_mode
hints->tx_attr->tclass = FI_TC_BULK_DATA
ret = run() -> static int run(void)
  ret = ft_init_fabric()
    ft_init_oob() -> fabtests:仅允许更改 OOB 地址 如果提供程序使用带有 -F 标志的 FI_ADDR_STR,则它可能不是 IP 地址,因此它不能用于与套接字的带外通信。 这会添加一个“-O”标志来选择带外地址,使其兼容
    ft_open_fabric_res
      fi_eq_open -> int ofi_eq_create(struct fid_fabric *fabric_fid, struct fi_eq_attr *attr, struct fid_eq **eq_fid, void *context)
        eq = calloc(1, sizeof(*eq))
        ret = ofi_eq_init(fabric_fid, attr, &eq->eq_fid, context)
          util_verify_eq_attr
            case FI_WAIT_YIELD -> 释放cpu
          util_eq_init
            ret = fi_wait_open(fabric, &wait_attr, &wait) -> int ofi_wait_fd_open
              ...
              wait->wait_obj = FI_WAIT_FD
              pollset->poll_fid.fid.fclass = FI_CLASS_POLL -> 类型
              pollset->poll_fid.fid.ops = &util_poll_fi_ops
              pollset->poll_fid.ops = &util_poll_ops
              ...
              wait->util_wait.signal = util_wait_fd_signal;
	            wait->util_wait.wait_try = util_wait_fd_try;
              ...
              ret = socketpair(AF_UNIX, SOCK_STREAM, 0, signal->fd)
              static inline int ofi_epoll_create -> *ep = epoll_create(4)
              ret = ofi_epoll_add(wait_fd->epoll_fd, fd, ofi_poll_to_epoll(events), context)
                static inline int ofi_epoll_add
                  event.events = events
                  ret = epoll_ctl(ep, EPOLL_CTL_ADD, fd, &event)
              wait->util_wait.wait_fid.fid.ops = &util_wait_fd_fi_ops;
	            wait->util_wait.wait_fid.ops = &util_wait_fd_ops;
            ret = fi_poll_add(&eq->wait->pollset->poll_fid -> 在添加到等待集之前,EQ 必须完全运行
              fid_list_insert(&pollset->fid_list, &pollset->lock, event_fid)

...
ret = ft_init_av()
  int ft_init_av_dst_addr
    ret = ft_get_rx_comp(rx_seq)
      ft_get_cq_comp(rxcq, &rx_cq_cntr, total, timeout)
        ft_read_cq(cq, cur, total, timeout, ft_tag)
          ft_spin_for_comp(cq, cur, total, timeout, tag)
            do loop -> fi_cq_read(cq, &comp, 1) -> 读完成队列, 检查时间
              ... ssize_t ofi_cq_readfrom ...
    ret = ft_post_rx(ep, rx_size, &rx_ctx)  
      FT_POST(fi_recv, ft_progress, rxcq, rx_seq, &rx_cq_cntr
    ret = (int) ft_tx(ep, *remote_addr, 1, &tx_ctx)
      ft_post_tx
        FT_POST(fi_send, ft_progress, txcq, tx_seq -> 触发客户端 ret = ft_init_av() 收到消息, 继续执行, 交换key的逻辑: ft_exchange_keys(&remote)
  ret = ft_exchange_keys(&remote)
    ret = fi_mr_raw_attr(mr, &addr, NULL, &key_size, 0)
    ret = ft_tx(ep, remote_fi_addr, len + ft_tx_prefix_size(), &tx_ctx)
    ret = ft_get_rx_comp(rx_seq)
  ft_post_rma_inject -> fabtests/benchmarks:修复注入大小设置 基准测试的“-j”选项允许用户指定注入大小的上限。 例如,可以通过将注入大小设置为 0 来禁用注入调用。该值通过提示传递给 fi_getinfo()。 但是,某些提供程序(例如 rxm)可能会报告比提示中要求的注入大小更高的注入大小。 当使用“-j”选项来尊重用户输入时,从提示中获取值
  基准测试:将注入操作作为 pingpong 的一部分 允许在输入上指定注入大小,并让 pingpong 测试在消息符合条件时使用注入。 删除inject_pingpong 测试,因为它现在已集成为其他基准测试的一部分。 在hints结构中设置注入值,然后使用输出fi_info结构提供的值
ft_free_res()

提交接收后立即progress
FT_POST(fi_recv, ft_progress, rxcq, rx_seq, &rx_cq_cntr


client: gdb --args fi_rma_bw -e rdm -o write -I 5 -p verbs 172.17.29.63
...
ret = ft_init_av() -> av: 18446744073709551615
  fi_av_insert -> static int rxm_av_insert
    ofi_ip_av_insert(av_fid, addr, count, fi_addr, flags, context)
      entry = ofi_ibuf_alloc(av->av_entry_pool)
      HASH_ADD(hh, av->hash, data, av->addrlen, entry) -> 插入hash表
    ret = rxm_av_add_peers(av, addr, count, fi_addr)

...
init_test(&opts, test_name, sizeof(test_name))
ret = bandwidth_rma(opts.rma_op, &remote)
  ret = ft_post_rma_inject(FT_RMA_WRITE, tx_buf + offset -> 发送数据, static void rxm_init_infos(void), buffer_size, 从历史上看,“buffer_size”是为急切消息大小指定的名称。 保留名称以实现向后兼容性, prov/rxm:缓冲区、eager 和数据包大小的单独定义 rxm_buffer_size 和 rxm_eager_limit 在整个代码中使用,具有特定含义。 特别是, eager_limit 可以表示 eager 消息协议的最大大小或反弹缓冲区的大小(相对于用户)。 后者令人困惑,因为 buffer_size 具有类似的含义,但其值不合适。 buffer_size 等于 eager_limit + rxm_pkt 的大小。 将 buffer_size 更新为等于分配的缓冲区的大小。 Eager 大小将与 Eager 协议相关的大小相对应。 并添加一个新的 packet_size 变量来记录分配的数据包的完整大小。 更新代码以引用提供有关如何使用值的最佳含义的变量。 这将允许未来的补丁允许这些值有所不同。 例如, eager_limit 和 buffer_size 不需要匹配


...
ret = ft_post_rma(FT_RMA_WRITE, tx_buf + offset
  static ssize_t rxm_ep_write
    struct fi_rma_iov rma_iov
    rxm_ep_generic_writemsg(ep_fid, &msg, rxm_ep->util_ep.tx_op_flags)
      vrb_msg_ep_rma_writemsg
        struct ibv_send_wr wr = {
          .wr_id = (uintptr_t)msg->context,
          .wr.rdma.remote_addr = msg->rma_iov->addr,
          .wr.rdma.rkey = (uint32_t)msg->rma_iov->key,
        };
        wr.opcode = IBV_WR_RDMA_WRITE
        ...
        wr->sg_list = alloca(sizeof(*wr->sg_list) * count)
        if (wr->send_flags & IBV_SEND_INLINE)
        ret = ofi_copy_from_hmem_iov(bounce_buf, len, iface, device, iov, count, 0)
          ofi_iov_bytes_to_copy
        wr->sg_list[0] = vrb_init_sge(bounce_buf, len, NULL)
        wr->num_sge = 1
        wr->wr_id = VERBS_COMP_FLAGS(ep, flags, wr->wr_id)
        if (flags & FI_FENCE) -> 设置 FENCE标签
          wr->send_flags |= IBV_SEND_FENCE
        ssize_t vrb_post_send
        ...    
fi_domain
  rxm_domain_open -> vrb_domain
    vrb_open_device_by_name
      ev_list = rdma_get_devices(NULL) -> 获取所有的rdma设备
      for (i = 0; dev_list[i] && ret; i++) -> 遍历设备列表
        const char *rdma_name = ibv_get_device_name(dev_list[i]->device)
    _domain->pd = ibv_alloc_pd(_domain->verbs)
    vrb_odp_flag
      ret = ibv_query_device_ex(verbs, &input, &attr)
    _domain->util_domain.domain_fid.fid.ops = &vrb_fid_ops; -> 
	  _domain->util_domain.domain_fid.mr = &vrb_mr_ops; -> 注册内存
    _domain->cache.add_region = vrb_mr_cache_add_region
    _domain->cache.delete_region = vrb_mr_cache_delete_region
    ret = ofi_mr_cache_init(&_domain->util_domain, memory_monitors, &_domain->cache)
      ofi_rbmap_init
      ofi_bufpool_create
        pool->entry_size = ofi_get_aligned_size(entry_sz, pool->attr.alignment)
    ret = vrb_init_progress(&_domain->progress, _domain->verbs)









    lock, enum ofi_lock_type, 初始化锁: int ofi_genlock_init, 
    core/lock:添加完全禁用同步锁的功能 同步锁支持无操作选项,该选项禁用锁定以支持单线程环境。 但是,它仍然在调试模式下使用互斥体来验证锁是否被正确使用。 此选项不适用于 tcp rdm 提供程序,因为使用更高级别的锁来避免进一步嵌套的锁定问题。 嵌套锁被转换为无操作,但可能会递归地“获取”(这就是它们被禁用的原因)。 更改 OFI_LOCK_NONE 选项以指示不需要锁定并且应禁用调试检查。 添加新的 OFI_LOCK_NOOP 来指示需要锁定,但应该是无操作

    核心:添加通用锁实现抽象提供一个锁,可以根据调用者的需要在互斥锁或自旋锁(或无锁)之间进行转换。 此抽象将取代 CQ 使用的锁抽象,并可由其他 util 类使用



#define DEFAULT_CONF_FILE_PATH "libfabric.conf" -> 默认配置文件
定义参数:
rxm_buffer_size 16KB
RXM_INI
{
	fi_param_define(&rxm_prov, "buffer_size", FI_PARAM_SIZE_T,
			"Defines the allocated buffer size used for bounce "
			"buffers, including buffers posted at the receive side "
			"to handle unexpected messages.  This value "
			"corresponds to the rxm inject limit, and is also "
			"typically used as the eager message size. "
			"(default %zu)", rxm_buffer_size);
comp_per_progress: 每轮一个
sar_limit: 分割与重组, prov/rxm:允许指定与缓冲区大小分开的急切大小 对于 rxm + tcp,急切大小和缓冲区大小可以不同。 Tcp 允许直接使用 tcp 发布用户缓冲区,从而避免发送端副本。 在接收端,只有在意外消息的情况下才需要缓冲区大小,我们可以单独处理。 (在后续补丁中)。 此更改将使我们能够避免在常见情况下不使用的缓冲区分配,从而减少通过 tcp 运行时的内存占用
enable_passthru: 直通, 启用 passthru 优化。Passthru 允许 rxm 将所有数据传输调用直接传递到核心提供程序,从而消除 rxm 协议和相关开销。Passthru 是到 tcp 提供程序的优化路径,具体取决于 应用程序请求的功能,


rdma发送标记:
enum ibv_send_flags {
	IBV_SEND_FENCE		= 1 << 0,
	IBV_SEND_SIGNALED	= 1 << 1,
	IBV_SEND_SOLICITED	= 1 << 2,
	IBV_SEND_INLINE		= 1 << 3,
	IBV_SEND_IP_CSUM	= 1 << 4
};

晓兵(ssbandjl)

博客: https://logread.cn | https://blog.csdn.net/ssbandjl | https://cloud.tencent.com/developer/user/5060293/articles

DAOS汇总: https://cloud.tencent.com/developer/article/2344030

公众号: 云原生云

晓兵技术杂谈(系列)

https://cloud.tencent.com/developer/user/5060293/video

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 晓兵(ssbandjl)
  • 晓兵技术杂谈(系列)
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档