static int read_events(size_t count, uint64_t flags) { struct fi_eq_entry entry; uint32_t event; size_t i; int ret; for (i = 0; i < count; i++) { memset(&entry, 0, sizeof(entry)); event = 0; ret = fi_eq_read(eq, &event, &entry, sizeof(entry), flags); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_read ret=%d, %s", ret, fi_strerror(-ret)); return ret; } if (event != FI_NOTIFY) { sprintf(err_buf, "iter %zu: event = %d, should be %d\n", i, event, FI_NOTIFY); return -FI_EOTHER; } } return FI_SUCCESS; }
static ssize_t hook_eq_read(struct fid_eq *eq, uint32_t *event, void *buf, size_t len, uint64_t flags) { struct hook_eq *myeq = container_of(eq, struct hook_eq, eq); ssize_t ret; ret = fi_eq_read(myeq->heq, event, buf, len, flags); if ((ret > 0) && hook_eq_std_event(*event)) hook_eq_map_fid(buf); return ret; }
static ssize_t ofi_eq_sread(struct fid_eq *eq_fid, uint32_t *event, void *buf, size_t len, int timeout, uint64_t flags) { struct util_eq *eq; eq = container_of(eq_fid, struct util_eq, eq_fid); if (!eq->internal_wait) { FI_WARN(eq->prov, FI_LOG_EQ, "EQ not configured for sread\n"); return -FI_ENOSYS; } fi_wait(&eq->wait->wait_fid, timeout); return fi_eq_read(eq_fid, event, buf, len, flags); }
int cm_server_finish_connect(void) { uint32_t event; struct fi_eq_cm_entry entry; ssize_t rd; rd = fi_eq_read(srv_eq, &event, &entry, sizeof(entry), 0); if (rd > 0) { dbg_printf("got event: %d\n", event); cr_assert(rd == sizeof(entry)); cr_assert(event == FI_CONNECTED && entry.fid == &srv_ep->fid); return 1; } return 0; }
int cm_client_finish_connect(void) { uint32_t event; ssize_t rd; struct fi_eq_cm_entry *entry; void *eqe_buf[EQE_SIZE] = {0}; rd = fi_eq_read(cli_eq, &event, eqe_buf, EQE_SIZE, 0); if (rd > 0) { dbg_printf("got event: %d\n", event); entry = (struct fi_eq_cm_entry *)eqe_buf; cr_assert(rd == (sizeof(*entry) + strlen(srv_cm_in_data))); cr_assert(event == FI_CONNECTED && entry->fid == &cli_ep->fid); cr_assert(!memcmp(srv_cm_in_data, entry->data, strlen(srv_cm_in_data))); return 1; } return 0; }
static void test_connect_with_accept_blocking_on_eq_fq_CLIENT(void) { int ret; printf("CLIENT running\n"); // Get the server's node (IP addr) and service (port) MPI_Recv(ofi_node, sizeof(ofi_node) - 1, MPI_CHAR, 0, 101, MPI_COMM_WORLD, MPI_STATUS_IGNORE); MPI_Recv(ofi_service, sizeof(ofi_service) - 1, MPI_CHAR, 0, 102, MPI_COMM_WORLD, MPI_STATUS_IGNORE); printf("CLIENT received via MPI: %s / %s\n", ofi_node, ofi_service); //setup_ofi(ofi_node, ofi_service); setup_ofi(NULL, NULL, 0); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; inet_aton(ofi_node, &sin.sin_addr); sin.sin_port = htons(atoi(ofi_service)); printf("CLIENT translated: %s\n", addrstr(&sin)); setup_ofi_active(fidev.info, &ficonn.ep); // Print server addr printf("CLIENT connecting to %s\n", addrstr(&sin)); // Connect! printf("Client connecting...\n"); ret = fi_connect(ficonn.ep, //fidev.info->dest_addr, &sin, (void*) client_data, sizeof(client_data)); if (ret < 0) { error("fi_connect failed"); } #if WANT_FDS // Now wait for the listen to complete int nevents; #define NEVENTS 32 struct epoll_event events[NEVENTS]; int timeout = 10000; while (1) { printf("CLIENT blocking on epoll\n"); nevents = epoll_wait(epoll_fd, events, NEVENTS, timeout); if (nevents < 0) { if (errno != EINTR) { error("client epoll wait failed"); } else { continue; } } else { printf("CLIENT successfully woke up from epoll! %d events\n", nevents); for (int i = 0; i < nevents; ++i) { if (events[i].data.u32 != 2222) { error("CLIENT unexpected epoll return type"); } } // If we got the expected event, then go read from the EQ break; } } #endif // Wait for FI_CONNECTED event uint32_t event; uint8_t *entry_buffer; size_t expected_len = sizeof(struct fi_eq_cm_entry) + sizeof(client_data); entry_buffer = (uint8_t*) calloc(1, expected_len); if (NULL == entry_buffer) { error("calloc failed"); } struct fi_eq_cm_entry *entry = (struct fi_eq_cm_entry*) entry_buffer; while (1) { printf("CLIENT waiting for FI_CONNECTED\n"); #if WANT_FDS ret = fi_eq_read(fidev.eq, &event, entry, expected_len, 0); #else ret = fi_eq_sread(fidev.eq, &event, entry, expected_len, -1, 0); #endif if (-FI_EAVAIL == ret) { fprintf(stderr, "client fi_eq_sread failed because there's something in the error queue\n"); char buffer[2048]; struct fi_eq_err_entry *err_entry = (struct fi_eq_err_entry*) buffer; ret = fi_eq_readerr(fidev.eq, err_entry, 0); fprintf(stderr, "error code: %d (%s), prov err code: %d (%s)\n", err_entry->err, fi_strerror(err_entry->err), err_entry->prov_errno, fi_strerror(err_entry->prov_errno)); error("sad panda"); } else if (ret == -EAGAIN) { fprintf(stderr, "CLIENT fi_eq_sread fail got -EAGAIN... trying again...\n"); sleep(1); continue; } else if (ret < 0) { fprintf(stderr, "SERVER fi_eq_sread fail: %s, ret = %d)\n", fi_strerror(-ret), ret); error("client fi_eq_sread failed for some random reason"); } else if (event != FI_CONNECTED) { error("client got some unexpected event"); } else if (ret != expected_len) { error("client got wrong length back from fi_eq_sread"); } uint32_t *d = (uint32_t*) entry->data; for (int i = 0; i < (sizeof(server_data) / sizeof(uint32_t)); ++i) { if (d[i] != server_data[i]) { printf("CLIENT got wrong CM client data: d[%d]=%d, should be %d\n", i, d[i], server_data[i]); } } printf("client got FI_CONNECTED, correct size, and correct data -- yay!\n"); break; } printf("CLIENT connecting -- waiting for server before sending\n"); MPI_Barrier(MPI_COMM_WORLD); sleep(1); int msg[4] = { 99, 100, 101, 102 }; int len = sizeof(msg); printf("CLIENT sending len of %d\n", len); struct fid_mr no_mr; struct fid_mr *mr; void *send_context = (void*) 0x42; #if 0 fi_mr_reg(fidev.domain, msg, len, FI_SEND | FI_RECV, 0, (uint64_t)(uintptr_t) msg, 0, &mr, NULL); #else // Try using no mr, like fi_msg_pingpong... memset(&no_mr, 0, sizeof(no_mr)); mr = &no_mr; #endif ret = fi_send(ficonn.ep, msg, len, fi_mr_desc(mr), 0, send_context); if (ret < 0) { printf("fi_Send failed! %d, %s\n", ret, fi_strerror(-ret)); MPI_Abort(MPI_COMM_WORLD, 37); } // Wait for send completion struct fi_cq_entry cqe; while (1) { ret = fi_cq_sread(ficonn.cq, &cqe, 1, 0, -1); if (cqe.op_context == send_context) { printf("CLIENT send completed\n"); break; } else { printf("CLIENT got some other completion... continuing\n"); } } printf("CLIENT sent -- waiting for server before teardown\n"); MPI_Barrier(MPI_COMM_WORLD); printf("CLIENT tearing down\n"); fi_close(&(mr->fid)); teardown_ofi(); }
static void test_connect_with_accept_blocking_on_eq_fq_SERVER(void) { int ret; printf("SERVER running\n"); setup_ofi(NULL, NULL, FI_SOURCE); #if WANT_FDS // Add the EQ FD to the epoll fd static struct epoll_event edt; memset(&edt, 0, sizeof(edt)); edt.events = EPOLLIN; edt.data.u32 = 2222; ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fidev.eq_fd, &edt); if (ret < 0) { error("server epoll_ctl failed"); } #endif // Make a PEP ret = fi_passive_ep(fidev.fabric, fidev.info, &fidev.pep, NULL); if (0 != ret) { error("fi_passive_ep failed"); } #if WANT_FIXED_PORT size_t ss = sizeof(sin); ret = fi_getname(&(fidev.pep->fid), &sin, &ss); if (0 != ret) { error("fi_setname failed"); } sin.sin_port = htons(listen_port); // Bind the PEP to listen on a specific port ret = fi_setname(&(fidev.pep->fid), &sin, sizeof(sin)); if (0 != ret) { error("fi_setname failed"); } #endif // Bind the EQ to the PEP ret = fi_pep_bind(fidev.pep, &fidev.eq->fid, 0); if (0 != ret) { error("fi_pep_bind failed"); } // Listen ret = fi_listen(fidev.pep); if (0 != ret) { error("fi_listen failed"); } // Get the actual address of this PEP struct sockaddr_in sinout; size_t s = sizeof(sinout); ret = fi_getname(&(fidev.pep->fid), &sinout, &s); if (0 != ret) { error("fi_setname failed"); } sin.sin_family = sinout.sin_family; sin.sin_addr = sinout.sin_addr; sin.sin_port = sinout.sin_port; // Print server addr printf("SERVER listening on %s\n", addrstr(&sin)); // Send our node (IP addr) and service (port) to the client snprintf(ofi_node, sizeof(ofi_node) - 1, "%s", inet_ntoa(sin.sin_addr)); snprintf(ofi_service, sizeof(ofi_service) - 1, "%d", ntohs(sin.sin_port)); MPI_Send(ofi_node, sizeof(ofi_node) - 1, MPI_CHAR, 1, 101, MPI_COMM_WORLD); MPI_Send(ofi_service, sizeof(ofi_service) - 1, MPI_CHAR, 1, 102, MPI_COMM_WORLD); printf("SERVER sent via MPI to client: %s / %s\n", ofi_node, ofi_service); #if WANT_FDS // Now wait for the listen to complete int nevents; #define NEVENTS 32 struct epoll_event events[NEVENTS]; int timeout = 10000; while (1) { printf("SERVER blocking on epoll\n"); nevents = epoll_wait(epoll_fd, events, NEVENTS, timeout); if (nevents < 0) { if (errno != EINTR) { error("server epoll wait failed"); } else { continue; } } else { printf("SERVER successfully woke up from epoll! %d events\n", nevents); for (int i = 0; i < nevents; ++i) { if (events[i].data.u32 != 2222) { error("server unexpected epoll return type"); } } // If we got the expected event, then go read from the EQ break; } } #endif // Wait for the FI_CONNREQ event uint32_t event; uint8_t *entry_buffer; size_t expected_len = sizeof(struct fi_eq_cm_entry) + sizeof(client_data); entry_buffer = (uint8_t*) calloc(1, expected_len); if (NULL == entry_buffer) { error("calloc failed"); } struct fi_eq_cm_entry *entry = (struct fi_eq_cm_entry*) entry_buffer; while (1) { printf("SERVER waiting for FI_CONNREQ\n"); #if WANT_FDS ret = fi_eq_read(fidev.eq, &event, entry, expected_len, 0); #else ret = fi_eq_sread(fidev.eq, &event, entry, expected_len, -1, 0); #endif if (-FI_EAVAIL == ret) { printf("server fi_eq_sread failed because there's something in the error queue\n"); char buffer[2048]; struct fi_eq_err_entry *err_entry = (struct fi_eq_err_entry*) buffer; ret = fi_eq_readerr(fidev.eq, err_entry, 0); printf("error code: %d (%s), prov err code: %d (%s)\n", err_entry->err, fi_strerror(err_entry->err), err_entry->prov_errno, fi_strerror(err_entry->prov_errno)); error("sad panda"); } else if (-EAGAIN == ret) { fprintf(stderr, "SERVER fi_eq_sread fail got -EAGAIN... trying again...\n"); sleep(1); continue; } else if (ret < 0) { fprintf(stderr, "SERVER fi_eq_sread fail: %s (FI_EAVAIL = %d, -ret = %d)\n", fi_strerror(-ret), FI_EAVAIL, -ret); error("SERVER fi_eq_sread failed for some random reason"); } else if (event != FI_CONNREQ) { error("SERVER got some unexpected event"); } else if (ret != expected_len) { error("SERVER got wrong length back from fi_eq_sread"); } uint32_t *d = (uint32_t*) entry->data; for (int i = 0; i < (sizeof(client_data) / sizeof(uint32_t)); ++i) { if (d[i] != client_data[i]) { printf("SERVER got wrong CM client data: d[%d]=%d, should be %d\n", i, d[i], client_data[i]); } } printf("SERVER got FI_CONNREQ, correct size, and correct data -- yay!\n"); break; } // Silly logistics: setup_ofi_active adds the fd to the epoll set. // But we already added it. So for simplicity, just remove it // here so that setup_ofi_active() can re-add it. #if WANT_FDS // Remove the EQ FD from the epoll fd ret = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fidev.eq_fd, &edt); if (ret < 0) { error("server epoll_ctl DEL failed"); } #endif // Make an active endpoint setup_ofi_active(entry->info, &ficonn.ep); // Accept the incoming connection ret = fi_accept(ficonn.ep, (void*) server_data, sizeof(server_data)); if (ret != 0) { printf("fi_accept: ret=%d, %s\n", ret, fi_strerror(-ret)); error("SERVER fi_accept failed\n"); } // Need to read and get a FI_CONNECTED event while (1) { printf("SERVER waiting for FI_CONNECTED\n"); #if WANT_FDS ret = fi_eq_read(fidev.eq, &event, entry, expected_len, 0); #else ret = fi_eq_sread(fidev.eq, &event, entry, expected_len, -1, 0); #endif if (-FI_EAVAIL == ret) { printf("server fi_eq_sread failed because there's something in the error queue\n"); char buffer[2048]; struct fi_eq_err_entry *err_entry = (struct fi_eq_err_entry*) buffer; ret = fi_eq_readerr(fidev.eq, err_entry, 0); printf("error code: %d (%s), prov err code: %d (%s)\n", err_entry->err, fi_strerror(err_entry->err), err_entry->prov_errno, fi_strerror(err_entry->prov_errno)); error("sad panda"); } else if (-EAGAIN == ret) { fprintf(stderr, "SERVER fi_eq_sread fail got -EAGAIN... trying again...\n"); sleep(1); continue; } else if (ret < 0) { fprintf(stderr, "SERVER fi_eq_sread fail: %s (FI_EAVAIL = %d, -ret = %d)\n", fi_strerror(-ret), FI_EAVAIL, -ret); error("SERVER fi_eq_sread failed for some random reason"); } else if (event != FI_CONNECTED) { error("SERVER got some unexpected event"); } printf("SERVER got FI_CONNECTED -- yay!\n"); break; } // Post a recv buffer for the client to send int msg[4] = { 0 }; int len = sizeof(msg); printf("SERVER receiving len of %d\n", len); struct fid_mr no_mr; struct fid_mr *mr; void *recv_context = (void*) 0x17; #if 0 fi_mr_reg(fidev.domain, msg, len, FI_SEND | FI_RECV, 0, (uint64_t)(uintptr_t) msg, 0, &mr, NULL); #else // Try using no mr, like fi_msg_pingpong... memset(&no_mr, 0, sizeof(no_mr)); mr = &no_mr; #endif ret = fi_recv(ficonn.ep, msg, len, fi_mr_desc(mr), 0, recv_context); if (ret < 0) { printf("fi_recv failed! %d, %s\n", ret, fi_strerror(-ret)); MPI_Abort(MPI_COMM_WORLD, 37); } sleep(1); printf("SERVER posted receive -- waiting for client to send\n"); MPI_Barrier(MPI_COMM_WORLD); // Wait for receive completion struct fi_cq_entry cqe; while (1) { ret = fi_cq_sread(ficonn.cq, &cqe, 1, 0, -1); if (cqe.op_context == recv_context) { printf("SERVER receive completed\n"); break; } else { printf("SERVER got some other completion... continuing\n"); } } printf("SERVER finished -- waiting for client before teardown\n"); MPI_Barrier(MPI_COMM_WORLD); printf("SERVER tearing down\n"); fi_close(&(mr->fid)); teardown_ofi(); }
/* * Tests: * - writing to EQ * - reading from EQ with and without FI_PEEK * - underflow read */ static int eq_write_read_self() { struct fi_eq_entry entry; uint32_t event; int testret; int ret; int i; testret = FAIL; ret = create_eq(32, FI_WRITE, FI_WAIT_NONE); if (ret != 0) { sprintf(err_buf, "fi_eq_open ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } /* Insert some events */ for (i = 0; i < 5; ++i) { if (i & 1) { entry.fid = &fabric->fid; } else { entry.fid = &eq->fid; } entry.context = (void *)(uintptr_t)i; ret = fi_eq_write(eq, FI_NOTIFY, &entry, sizeof(entry), 0); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_write ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } } /* Now read them back, peeking first at each one */ for (i = 0; i < 10; ++i) { event = ~0; memset(&entry, 0, sizeof(entry)); ret = fi_eq_read(eq, &event, &entry, sizeof(entry), (i & 1) ? 0 : FI_PEEK); if (ret != sizeof(entry)) { sprintf(err_buf, "fi_eq_read ret=%d, %s", ret, fi_strerror(-ret)); goto fail; } if (event != FI_NOTIFY) { sprintf(err_buf, "iter %d: event = %d, should be %d\n", i, event, FI_NOTIFY); goto fail; } if ((int)(uintptr_t)entry.context != i / 2) { sprintf(err_buf, "iter %d: context mismatch %d != %d", i, (int)(uintptr_t)entry.context, i / 2); goto fail; } if (entry.fid != ((i & 2) ? &fabric->fid : &eq->fid)) { sprintf(err_buf, "iter %d: fid mismatch %p != %p", i, entry.fid, ((i & 2) ? &fabric->fid : &eq->fid)); goto fail; } } /* queue is now empty */ ret = fi_eq_read(eq, &event, &entry, sizeof(entry), 0); if (ret != -FI_EAGAIN) { sprintf(err_buf, "fi_eq_read of empty EQ returned %d", ret); goto fail; } testret = PASS; fail: FT_CLOSE_FID(eq); return TEST_RET_VAL(ret, testret); }