2

RDMA_CM ライブラリを使用して RDMA プログラミングを行った人はいますか?

勉強する簡単な例でさえ見つけるのに苦労しています。librdmacm に rdma_client & rdma_server の例がありますが、ループでは実行されません (rping はループしますが、rdma_cm 関数の代わりに IB 動詞を直接使用して記述されています)。

簡単なピンポン プログラムを作成しましたが、1 回から 100 回のバウンス後にどこでもロックしてしまいます。クライアント内にスリープを追加すると、競合状態を示すハングするまでの時間が長くなることがわかりました。

クライアントは rdma_get_send_comp() でスタックし、サーバーは rdma_get_recv_comp() でスタックします。

私の限られた理解は、すべての rdma_post_send() の前に、送信後に来る rdma_post_recv() を発行する必要があるということです。また、すべての送信 (最初のクライアント送信を除く) の前に、相手側が受信する準備ができていることを示すメッセージ (rdma_get_recv()) を待つ必要があります。

何が間違っている可能性がありますか?

Server(rdma_cm_id *id)
{
    ibv_wc wc;

    int ret;
    uint8_t recvBuffer[MESSAGE_BUFFER_SIZE],
            sendBuffer[MESSAGE_BUFFER_SIZE];

    ibv_mr *recvMemRegion =  rdma_reg_msgs(id, recvBuffer, MESSAGE_BUFFER_SIZE);
    if (!recvMemRegion)
      throw 0;

    ibv_mr *sendMemRegion = rdma_reg_msgs(id, sendBuffer, MESSAGE_BUFFER_SIZE);
    if (!sendMemRegion)
      throw 0;


    if (ret = rdma_post_recv(id, NULL, recvBuffer, 1, recvMemRegion))
      throw 0;


    if (ret = rdma_accept(id, NULL))
       throw 0;

    do
    {
        if ((ret = rdma_get_recv_comp(id, &wc)) <= 0)
            throw 0;

        if (ret = rdma_post_recv(id, NULL, recvBuffer, 1, recvMemRegion))
          throw 0;

        if (ret = rdma_post_send(id, NULL, sendBuffer, 1, sendMemRegion, 0))
           throw 0;

        printf(".");
        fflush(stdout);

        if ((ret = rdma_get_send_comp(id, &wc)) <= 0)
          throw 0;
    }
    while (true);
}

Client()   // sends the 1st message
{
    // queue-pair parameters are:
    attr.cap.max_send_wr = attr.cap.max_recv_wr = 4;
    attr.cap.max_send_sge = attr.cap.max_recv_sge = 2;
    attr.cap.max_inline_data = 16;
    attr.qp_context = id;
    attr.sq_sig_all = 1;
    attr.qp_type = IBV_QPT_RC;

    <create connection boiler plate>

    uint8_t recvBuffer[MESSAGE_BUFFER_SIZE],
            sendBuffer[MESSAGE_BUFFER_SIZE];

    recvMemRegion = rdma_reg_msgs(id, recvBuffer, MESSAGE_BUFFER_SIZE);
    if (!recvMemRegion)
        throw 0;

    sendMemRegion = rdma_reg_msgs(id, sendBuffer, MESSAGE_BUFFER_SIZE);
    if (!sendMemRegion)
        throw 0;

    if (ret = rdma_connect(id, NULL))
      throw 0;

    do
    {
        if (ret = rdma_post_recv(id, NULL, recvBuffer, 1, recvMemRegion))
          throw 0;

        //usleep(5000);
        if (ret = rdma_post_send(id, NULL, sendBuffer, 1, sendMemRegion, 0))
          throw 0;

        if ((ret = rdma_get_send_comp(id, &wc)) <= 0)
           throw 0;

        if ((ret = rdma_get_recv_comp(id, &wc)) <= 0)
          throw 0;

        printf(".");
        fflush(stdout);
    } 
    while (true);
}
4

1 に答える 1

2

呪い!私は、SUSE 11 に付属していた librdmacm-1.0.15-1 (2012 年以降) のバグに悩まされていました。送信/受信シーケンスに問題がないことはわかっていました。

まず、自分のコードを他の例と比較してみました。私が見た一例では

while (!ibv_poll_cq(id->send_cq, 1, &wc));

rdma_get_send_comp() の代わりに、rdma_get_recv_comp() の場合も同様です。私の例でそれらを置き換えてみましたが、奇跡的にぶら下がっていました!

うーん、おそらく rdma_get_send_comp() は期待どおりに動作していません。コードを見たほうがいいと思います。1.0.15 と 1.0.18 の両方のコードを取得しましたが、rdma_verbs.h には何が表示されますか?

2 つの非常に異なる IB 動詞シーケンス:

// 1.0.15
rdma_get_send_comp(struct rdma_cm_id *id, struct ibv_wc *wc)
{
        struct ibv_cq *cq;
        void *context;
        int ret;

        ret = ibv_poll_cq(id->send_cq, 1, wc);
        if (ret)
                goto out;

        ret = ibv_req_notify_cq(id->send_cq, 0);
        if (ret)
                return rdma_seterrno(ret);

        while (!(ret = ibv_poll_cq(id->send_cq, 1, wc))) {
                ret = ibv_get_cq_event(id->send_cq_channel, &cq, &context);
                if (ret)
                        return rdma_seterrno(ret);

                assert(cq == id->send_cq && context == id);
                ibv_ack_cq_events(id->send_cq, 1);
        }
out:
        return (ret < 0) ? rdma_seterrno(ret) : ret;
}

vs
// 1.0.18
rdma_get_send_comp(struct rdma_cm_id *id, struct ibv_wc *wc)
{
        struct ibv_cq *cq;
        void *context;
        int ret;

        do {
                ret = ibv_poll_cq(id->send_cq, 1, wc);
                if (ret)
                        break;

                ret = ibv_req_notify_cq(id->send_cq, 0);
                if (ret)
                        return rdma_seterrno(ret);

                ret = ibv_poll_cq(id->send_cq, 1, wc);
                if (ret)
                        break;

                ret = ibv_get_cq_event(id->send_cq_channel, &cq, &context);
                if (ret)
                        return ret;

                assert(cq == id->send_cq && context == id);
                ibv_ack_cq_events(id->send_cq, 1);
        } while (1);

        return (ret < 0) ? rdma_seterrno(ret) : ret;
}

1.0.15 がランダムにハングするのに 1.0.18 が機能する理由を誰か説明できますか?

于 2015-08-08T09:36:24.640 に答える