asynchronous operation with poll()
I have a client and server test program to explore fully asynchronous communication written as close to a conventional sockets application as possible and am encountering difficulty.
Both programs run the same code in a thread, sending buffers to each other as fast as possible. On the client side only, my poll() call never blocks and cm_id->send_cq_channel->fd always seems to be readable. This causes the program to loop wildly and consume 100% CPU.
Any ideas? I have ensured that O_NONBLOCK is set on the underlying file descriptors. I'm not sure why the server side should run with almost no cpu usage yet the client does not.
Here is the client/server loop:
Quoted 169 lines
struct ibv_mr *mr; int ret; int send_buf_num = 0; int recv_buf_num = 0; #define NUM_BUFFERS 20 #define SIZE 1024*1024 uint8_t *buffer = (uint8_t*)malloc(SIZE * NUM_BUFFERS * 2); uint8_t *send_msg[NUM_BUFFERS]; uint8_t *recv_msg[NUM_BUFFERS]; for(int i=0; i<NUM_BUFFERS; i++) { send_msg[i] = buffer + (i*SIZE); recv_msg[i] = buffer + ((i+NUM_BUFFERS) * SIZE); } //-------------------------------------------------------------------- // setup fprintf(stderr, "rdma_reg_msgs\n"); mr = rdma_reg_msgs(cm_id, buffer, SIZE*NUM_BUFFERS*2); if (!mr) { perror("rdma_reg_msgs"); } //prepare to for the first receive before connecting for(int i=0; i<10; i++) { fprintf(stderr, "rdma_post_recv\n"); ret = rdma_post_recv(cm_id, NULL, recv_msg[recv_buf_num++], SIZE, mr); recv_buf_num %= NUM_BUFFERS; if (ret) { perror("rdma_post_recv"); } } //connect fprintf(stderr, "rdma_connect\n"); ret = rdma_connect(cm_id, NULL); if (ret) { perror("rdma_connect"); } const int NUM_FDS = 4; const int POLL_CM = 0; const int POLL_RECV_CQ = 1; const int POLL_SEND_CQ = 2; const int POLL_WAKE = 3; struct pollfd fds[NUM_FDS];//prime notification of events on the recv completion queue
ibv_req_notify_cq(cm_id->recv_cq, 0);
////-------------------------------------------------------------------- // main loop while(ret == 0) { memset(fds, 0, sizeof(pollfd) * NUM_FDS); fds[POLL_CM].fd = cm_channel->fd; fds[POLL_CM].events = POLLIN;fds[POLL_RECV_CQ].fd = cm_id->recv_cq_channel->fd; fds[POLL_RECV_CQ].events = POLLIN; fds[POLL_SEND_CQ].fd = cm_id->send_cq_channel->fd; fds[POLL_SEND_CQ].events = POLLIN; fds[POLL_WAKE].fd = wake_fds[0]; fds[POLL_WAKE].events = POLLIN; int nready = poll(fds, NUM_FDS, -1); if(nready < 0) { perror("poll"); } if(fds[POLL_CM].revents & POLLIN) { struct rdma_cm_event *cm_event; ret = rdma_get_cm_event(cm_channel, &cm_event); if(ret) { perror("client connection rdma_get_cm_event"); } fprintf(stderr, "Got cm event %s\n", rdma_event_str(cm_event->event)); if(cm_event->event == RDMA_CM_EVENT_ESTABLISHED) { //send as soon as we are connected ibv_req_notify_cq(cm_id->send_cq, 0); ret = rdma_post_send(cm_id, NULL, send_msg[send_buf_num], SIZE, mr, 0); send_buf_num++; send_buf_num %= NUM_BUFFERS; if (ret) { perror("rdma_post_send"); } } int finish=0; if(cm_event->event == RDMA_CM_EVENT_DISCONNECTED || cm_event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) finish = 1; rdma_ack_cm_event(cm_event); if(finish) { goto out; } } //if the send completed if(fds[POLL_SEND_CQ].revents & POLLIN) { struct ibv_cq *cq; struct ibv_wc wc[10]; void *context; int num_send = ibv_poll_cq(cm_id->send_cq, 10, &wc[0]); if(num_send == 0) fprintf(stderr, "."); for(int i=0; i<num_send; i++) { fprintf(stderr,"Got SEND CQ event : %d of %d %s\n", i, num_send, ibv_wc_status_str(wc[i].status)); ibv_get_cq_event(cm_id->send_cq_channel, &cq, &context); assert(cq == cm_id->send_cq); //our send completed, send some more right away fprintf(stderr, "rdma_post_send\n"); ret = rdma_post_send(cm_id, NULL, send_msg[send_buf_num++], SIZE, mr, 0); send_buf_num %= NUM_BUFFERS; if (ret) { perror("rdma_post_send"); } } //expensive call, ack all received events together ibv_ack_cq_events(cm_id->send_cq, num_send); ibv_req_notify_cq(cm_id->send_cq, 0); } //if the receive completed, prepare to receive more if(fds[POLL_RECV_CQ].revents & POLLIN) { struct ibv_cq *cq; struct ibv_wc wc[10]; void *context; int num_recv=ibv_poll_cq(cm_id->recv_cq, 10, &wc[0]); for(int i=0; i<num_recv; i++) { fprintf(stderr,"Got RECV CQ event : %d of %d %s\n", i, num_recv, ibv_wc_status_str(wc[i].status)); ibv_get_cq_event(cm_id->recv_cq_channel, &cq, &context); assert(cq == cm_id->recv_cq); //we received some payload, prepare to receive more fprintf(stderr, "rdma_post_recv\n"); ret = rdma_post_recv(cm_id, NULL, recv_msg[recv_buf_num++], SIZE, mr); recv_buf_num %= NUM_BUFFERS; if (ret) { perror("rdma_post_recv"); } } //expensive call, ack all received events together ibv_ack_cq_events(cm_id->recv_cq, num_recv); ibv_req_notify_cq(cm_id->recv_cq, 0); } if(fds[POLL_WAKE].revents & POLLIN) { fprintf(stderr, "poll WAKE\n"); char buffer[1]; int nread = read(wake_fds[0], buffer, 1); fprintf(stderr, "Got Wake event %d\n", nread); goto out; }}
Quoted 7 lines
out:
rdma_disconnect(cm_id);
rdma_dereg_mr(mr);
rdma_destroy_ep(cm_id);free(buffer); fprintf(stderr, "poll: client completed\n");
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 3 lines · Jonathan Rosser
I have a client and server test program to explore fully asynchronous communication written as close to a conventional sockets application as possible and am encountering difficulty.
Broadly it looks to me like your actions are in the wrong order. A poll based RDMA loop should look like this:
- exit poll
- Check poll bit
- call ibv_get_cq_event
- call ibv_req_notify_cq
- repeatedly call ibv_poll_cq (while rc == num requested)
- Issue new work
- return to poll
Generally, for your own sanity, I recommend splitting into 3 functions
- Do the stuff with ibv_get_cq_event
- Drain and process WC's
- Issue new work
Most real use cases will also want to call the latter two functions from other waiters in the poll loop (ie whatever your wak_fds is for).
Some random mild comments for you:
Quoted 6 lines
Quoted 6 lines
const int
NUM_FDS= 4;const int
POLL_CM= 0;
const intPOLL_RECV_CQ= 1;
const intPOLL_SEND_CQ= 2;
const intPOLL_WAKE= 3;
You can use an enum for these constants
Quoted 2 lines
Quoted 2 lines
//prime notification of events on the recv completion queue
ibv_req_notify_cq(cm_id->recv_cq, 0);
Do this earlier, before posting recvs, otherwise you could race getting your first recv.
Quoted 6 lines
Quoted 6 lines
while(ret == 0)
{ memset(fds, 0, sizeof(pollfd) * NUM_FDS); fds[POLL_CM].fd = cm_channel->fd; fds[POLL_CM].events = POLLIN;
Quoted 8 lines
Quoted 8 lines
fds[POLL_RECV_CQ].fd = cm_id->recv_cq_channel->fd; fds[POLL_RECV_CQ].events = POLLIN; fds[POLL_SEND_CQ].fd = cm_id->send_cq_channel->fd; fds[POLL_SEND_CQ].events = POLLIN; fds[POLL_WAKE].fd = wake_fds[0]; fds[POLL_WAKE].events = POLLIN;
The efficient use of poll does not put these inside the main loop. You only need to initialize fd and events once at the start.
Quoted 11 lines
Quoted 11 lines
if(fds[POLL_CM].revents & POLLIN) { struct rdma_cm_event *cm_event; ret = rdma_get_cm_event(cm_channel, &cm_event); if(ret) { perror("client connection rdma_get_cm_event"); } fprintf(stderr, "Got cm event %s\n", rdma_event_str(cm_event->event));if(cm_event->event == RDMA_CM_EVENT_ESTABLISHED) { //send as soon as we are connected ibv_req_notify_cq(cm_id->send_cq, 0);
Again, this should be done once, right after the cq is created.
Quoted 7 lines
Quoted 7 lines
//if the send completed if(fds[POLL_SEND_CQ].revents & POLLIN) { struct ibv_cq *cq; struct ibv_wc wc[10]; void *context; int num_send = ibv_poll_cq(cm_id->send_cq, 10, &wc[0]); if(num_send == 0) fprintf(stderr, ".");
Check that num_sends == 10 and loop again
Quoted 3 lines
Quoted 3 lines
for(int i=0; i<num_send; i++) { fprintf(stderr,"Got SEND CQ event : %d of %d %s\n", i, num_send, ibv_wc_status_str(wc[i].status)); ibv_get_cq_event(cm_id->send_cq_channel, &cq, &context);
cq_events are not tied to send WC's, this should be done exactly once, prior to calling ibv_poll_cq
Quoted 2 lines
Quoted 2 lines
//expensive call, ack all received events together ibv_ack_cq_events(cm_id->send_cq, num_send);
You don't have to do this at all in the loop unless you are doing multithreaded things. Using num_send is wrong, I use this:
bool checkCQPoll(struct pollfd &p)
{
if ((p.revents & POLLIN) == 0 ||
ibv_get_cq_event(comp,&jnk1,&jnk2) != 0)
return false;
compEvents++;
if (compEvents >= INT_MAX)
{
ibv_ack_cq_events(cq,compEvents);
compEvents = 0;
}
int rc;
if ((rc = ibv_req_notify_cq(cq,0)) == -1)
{
errno = rc;
[..]And then call ibv_ack_cq_events(cq,compEvents) before trying to destroy the CQ. All it used for it synchronizing exits between threads.
Quoted 1 line
Quoted 1 line
ibv_req_notify_cq(cm_id->send_cq, 0);
Do right after calling ibv_get_cq_event
Quoted 6 lines
Quoted 6 lines
//if the receive completed, prepare to receive more if(fds[POLL_RECV_CQ].revents & POLLIN) { struct ibv_cq *cq; struct ibv_wc wc[10]; void *context; int num_recv=ibv_poll_cq(cm_id->recv_cq, 10, &wc[0]);
Same problems as for send, they should be the same. Implement a function like my checkCQPoll example and call it for both cases.
Continually posting sends and recvs will get you into trouble, you will run out of recvs and get RNR's. These days the wisdom for implementing RDMA is that you should have explicit message flow control. Ie for something simple like this you could say that getting a recv means another send is OK, but you still need a mechanism to wait for a send buffer to be returned on the send CQ - there is no ordering guarantee.
Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 20101109204452.GG909-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/@public.gmane.org
Hi Jonathan,
I wrote down a test (latency and transfer speed) with RDMA. Server and client work with the same code and they change defined size buffers for n times (loop). In the makefile.txt, you can find an help to use the code.
I tested Intel NetEffect NE020 E10G81GP cards with this code and I found minimum latency about 11 us,maximum transfer speed about 9,6 GBytes, CPU usage up to 90% on client side.
The last value is not good for us.
I hope these help you.
Thank you,
Andrea
Andrea Gozzelino
INFN - Laboratori Nazionali di Legnaro (LNL)
Viale dell'Universita' 2 -I-35020 - Legnaro (PD)- ITALIA
Office: E-101
Tel: +39 049 8068346
Fax: +39 049 641925
Mail: andrea.gozzelino-PK20h7lG/[email protected]
Cell: +39 3488245552
Quoted 51 lines · Jason Gunthorpe
Quoted 3 lines · Jonathan Rosser
I have a client and server test program to explore fully asynchronous communication written as close to a conventional sockets application as possible and am encountering difficulty.
Broadly it looks to me like your actions are in the wrong order. A poll based RDMA loop should look like this:
- exit poll
- Check poll bit
- callibv_get_cq_event
- callibv_req_notify_cq
- repeatedly callibv_poll_cq(while rc == num requested)
- Issue new work
- return to pollGenerally, for your own sanity, I recommend splitting into 3 functions
- Do the stuff withibv_get_cq_event
- Drain and process WC's
- Issue new workMost real use cases will also want to call the latter two functions from other waiters in the poll loop (ie whatever your
wak_fdsis for).Some random mild comments for you:
Quoted 6 lines
Quoted 6 lines
const int
NUM_FDS= 4;const int
POLL_CM= 0;
const intPOLL_RECV_CQ= 1;
const intPOLL_SEND_CQ= 2;
const intPOLL_WAKE= 3;You can use an enum for these constants
Quoted 2 lines
Quoted 2 lines
//prime notification of events on the recv completion queue
ibv_req_notify_cq(cm_id->recv_cq, 0);Do this earlier, before posting recvs, otherwise you could race getting your first recv.
Quoted 9 lines
Quoted 9 lines
while(ret == 0)
{ memset(fds, 0, sizeof(pollfd) * NUM_FDS); fds[POLL_CM].fd = cm_channel->fd; fds[POLL_CM].events = POLLIN; fds[POLL_RECV_CQ].fd = cm_id->recv_cq_channel->fd; fds[POLL_RECV_CQ].events = POLLIN;
Quoted 16 lines
Quoted 5 lines
Quoted 5 lines
fds[POLL_SEND_CQ].fd = cm_id->send_cq_channel->fd; fds[POLL_SEND_CQ].events = POLLIN; fds[POLL_WAKE].fd = wake_fds[0]; fds[POLL_WAKE].events = POLLIN;The efficient use of poll does not put these inside the main loop. You only need to initialize fd and events once at the start.
Quoted 7 lines
Quoted 7 lines
if(fds[POLL_CM].revents & POLLIN) { struct rdma_cm_event *cm_event; ret = rdma_get_cm_event(cm_channel, &cm_event); if(ret) { perror("client connection rdma_get_cm_event"); } fprintf(stderr, "Got cm event %s
", rdma_event_str(cm_event->event));
Quoted 15 lines
Quoted 4 lines
Quoted 4 lines
if(cm_event->event == RDMA_CM_EVENT_ESTABLISHED) { //send as soon as we are connected ibv_req_notify_cq(cm_id->send_cq, 0);Again, this should be done once, right after the cq is created.
Quoted 7 lines
Quoted 7 lines
//if the send completed if(fds[POLL_SEND_CQ].revents & POLLIN) { struct ibv_cq *cq; struct ibv_wc wc[10]; void *context; int num_send = ibv_poll_cq(cm_id->send_cq, 10, &wc[0]); if(num_send == 0) fprintf(stderr, ".");
Quoted 4 lines
Check that
num_sends== 10 and loop againQuoted 2 lines
Quoted 2 lines
for(int i=0; i<num_send; i++){
fprintf(stderr,"Got SEND CQ event : %d of %d %s
", i, num_send, ibv_wc_status_str(wc[i].status));
Quoted 62 lines
Quoted 1 line
Quoted 1 line
ibv_get_cq_event(cm_id->send_cq_channel, &cq, &context);
cq_eventsare not tied to send WC's, this should be done exactly once, prior to callingibv_poll_cqQuoted 2 lines
Quoted 2 lines
//expensive call, ack all received events together ibv_ack_cq_events(cm_id->send_cq, num_send);You don't have to do this at all in the loop unless you are doing multithreaded things. Using
num_sendis wrong, I use this:bool
checkCQPoll(struct pollfd &p){ if ((p.revents & POLLIN) == 0 || ibv_get_cq_event(comp,&jnk1,&jnk2) != 0) return false; compEvents++; if (compEvents >= INT_MAX) { ibv_ack_cq_events(cq,compEvents); compEvents = 0; } int rc; if ((rc = ibv_req_notify_cq(cq,0)) == -1) { errno = rc; [..]And then call
ibv_ack_cq_events(cq,compEvents)before trying to destroy the CQ. All it used for it synchronizing exits between threads.Quoted 1 line
Quoted 1 line
ibv_req_notify_cq(cm_id->send_cq, 0);Do right after calling
ibv_get_cq_eventQuoted 6 lines
Quoted 6 lines
//if the receive completed, prepare to receive more if(fds[POLL_RECV_CQ].revents & POLLIN) { struct ibv_cq *cq; struct ibv_wc wc[10]; void *context; int num_recv=ibv_poll_cq(cm_id->recv_cq, 10, &wc[0]);Same problems as for send, they should be the same. Implement a function like my checkCQPoll example and call it for both cases.
Continually posting sends and recvs will get you into trouble, you will run out of recvs and get RNR's. These days the wisdom for implementing RDMA is that you should have explicit message flow control. Ie for something simple like this you could say that getting a recv means another send is OK, but you still need a mechanism to wait for a send buffer to be returned on the send CQ - there is no ordering guarantee.
Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): 4538690.1289385043068.SLOX.WebMail.wwwrun-XDIR3SKYeFbgKi2NxijLtw@public.gmane.org
Quoted 11 lines · Andrea Gozzelino
Hi Jonathan,
I wrote down a test (latency and transfer speed) with RDMA. Server and client work with the same code and they change defined size buffers for n times (loop). In the makefile.txt, you can find an help to use the code.
I tested Intel NetEffect NE020 E10G81GP cards with this code and I found minimum latency about 11 us,maximum transfer speed about 9,6 GBytes, CPU usage up to 90% on client side.
The last value is not good for us.
Hi Andrea,
Thanks for the code. With the advice from Jason I have changed my test program to get reliable communication using 1Mbyte buffers. The CPU usage is less than 2% on both client and server for 10Gb throughput. I have Chelsio S310CR.
I find using the poll() approach more natural as I have experience with conventional sockets based programming before.
The rdma_client/rdma_server example programs from librdmacm were the easiest to start from and I have incrementally changed them from synchronous to asynchronous operation, and moved the internals of the high level functions in <rdma/rdma_verbs.h> into my own code piece by piece. The learning curve is very steep :)
I found this paper quite interesting www.systems.ethz.ch/research/awards/minimizingthehidden.pdf
Cheers,
Jonathan.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 41 lines · Jonathan Rosser
Quoted 9 lines · Andrea Gozzelino
Hi Jonathan,
I wrote down a test (latency and transfer speed) with RDMA. Server and client work with the same code and they change defined size
buffers for n times (loop). In the makefile.txt, you can find an help to
use the code.Quoted 6 lines
I tested Intel NetEffect NE020 E10G81GP cards with this code and I found
minimum latency about 11 us,maximum transfer speed about 9,6 GBytes, CPU
usage up to 90% on client side.
The last value is not good for us.Hi Andrea,
Thanks for the code. With the advice from Jason I have changed my test program to get reliable communication using 1Mbyte buffers. The CPU usage is less than 2% on both client and server for 10Gb throughput. I have Chelsio S310CR.
I find using the
poll()approach more natural as I have experience with
conventional sockets based programming before.The rdma_client/rdma_server example programs from librdmacm were the easiest to start from and I have incrementally changed them from synchronous to asynchronous operation, and moved the internals of the high level functions in <
rdma/rdma_verbs.h> into my own code piece by piece. The learning curve is very steep :)I found this paper quite interesting www.systems.ethz.ch/research/awards/minimizingthehidden.pdf
Cheers,
Jonathan.
Quoted 6 lines
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Jonathan,
I would like testing my Intel NetEffect cards with your code, if it is possible.
Could you please send me the files client/server and the compiling commands?
Thank you very much for the pdf paper: I'm going to read it during the morning.
Cheers,
Andrea Gozzelino
INFN - Laboratori Nazionali di Legnaro (LNL)
Viale dell'Universita' 2 -I-35020 - Legnaro (PD)- ITALIA
Office: E-101
Tel: +39 049 8068346
Fax: +39 049 641925
Mail: andrea.gozzelino-PK20h7lG/[email protected]
Cell: +39 3488245552
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 11 lines · Jason Gunthorpe
Broadly it looks to me like your actions are in the wrong order. A poll based RDMA loop should look like this:
- exit poll
- Check poll bit
- callibv_get_cq_event
- callibv_req_notify_cq
- repeatedly callibv_poll_cq(while rc == num requested)
- Issue new work
- return to poll
Quoted 5 lines
Generally, for your own sanity, I recommend splitting into 3 functions
- Do the stuff withibv_get_cq_event
- Drain and process WC's
- Issue new work
Hi Jason,
Thanks very much for your advice. I had misunderstood the relationship between CQ events and available WC's.
Quoted 3 lines
doing multithreaded things. Using
num_sendis wrong, I use this:bool
checkCQPoll(struct pollfd&p)
Right - using a function like your checkCQPoll has sorted out the behaviour of the poll() loop.
Quoted 3 lines
Continually posting sends and recvs will get you into trouble, you will run out of recvs and get RNR's. These days the wisdom for implementing RDMA is that you should have explicit message flow
OK - I appreciate that a real world protocol ought to have flow control rather than just send as fast as possible. I've been trying to exercise the interfaces as far as possible and make sure my RDMA implementation is solid before building something real on top of it.
Quoted 4 lines
control. Ie for something simple like this you could say that getting a recv means another send is OK, but you still need a mechanism to wait for a send buffer to be returned on the send CQ - there is no ordering guarantee.
Could I get some clarification on where there is no ordering guarantee? The WC's do not necessarily come back in the order that the sends were posted?
Many Thanks,
Jonathan.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 3 lines
Could I get some clarification on where there is no ordering guarantee? The WC's do not necessarily come back in the order that the sends were posted?
For a given queue, completions are always returned in the order that work requests were posted. However there is no ordering between different queues.
- R.
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 7 lines · Roland Dreier
Quoted 3 lines
Could I get some clarification on where there is no ordering guarantee? The WC's do not necessarily come back in the order that the sends were posted?
For a given queue, completions are always returned in the order that work requests were posted. However there is no ordering between different queues.
Right, so if you design a scheme where getting a recv grants a send credit then you are doing
Post Send #1 ---> Recv WC
Recv WC <---- Post Send #2
Send WC #2 Send WC #2
PostSend #3 ---> Recv WC
and there is no order guarentee for when you get a Recv WC vs a Send WC, even though by protocol design they are in fact ordered. If you load the HCA the Send Complete WC's do get behind Recv WCs.
This is true even if you use the same CQ for Recv WC and Send Complete WCs.
In practice this can make the implementation quite troublesome since the posting of a new Send can't necessarily be done in the Recv WC path as no send buffers could be available at that time.
I've found properly placing all the activities in a RDMA system to be the hardest challenge of the whole design. Avoiding deadlock and starvation and untangling the various data dependencies can be hard :(
Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 8 lines · Jonathan Rosser
Quoted 3 lines
Continually posting sends and recvs will get you into trouble, you will run out of recvs and get RNR's. These days the wisdom for implementing RDMA is that you should have explicit message flow
OK - I appreciate that a real world protocol ought to have flow control rather than just send as fast as possible. I've been trying to exercise the interfaces as far as possible and make sure my RDMA implementation is solid before building something real on top of it.
With iWarp if you send more than the receiver is able to receive you will break the connection with an error. Some kind of flow control scheme is mandatory..
Jason
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html