1 /* 2 * Copyright (c) 2005 Topspin Communications. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 #define _GNU_SOURCE 33 #include <config.h> 34 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 #include <string.h> 39 #include <sys/types.h> 40 #include <sys/socket.h> 41 #include <sys/time.h> 42 #include <netdb.h> 43 #include <stdlib.h> 44 #include <getopt.h> 45 #include <arpa/inet.h> 46 #include <time.h> 47 48 #include "pingpong.h" 49 50 enum { 51 PINGPONG_RECV_WRID = 1, 52 PINGPONG_SEND_WRID = 2, 53 }; 54 55 static int page_size; 56 57 struct pingpong_context { 58 struct ibv_context *context; 59 struct ibv_comp_channel *channel; 60 struct ibv_pd *pd; 61 struct ibv_mr *mr; 62 struct ibv_cq *cq; 63 struct ibv_qp *qp; 64 void *buf; 65 int size; 66 int send_flags; 67 int rx_depth; 68 int pending; 69 struct ibv_port_attr portinfo; 70 }; 71 72 struct pingpong_dest { 73 int lid; 74 int qpn; 75 int psn; 76 union ibv_gid gid; 77 }; 78 79 static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn, 80 enum ibv_mtu mtu, int sl, 81 struct pingpong_dest *dest, int sgid_idx) 82 { 83 struct ibv_qp_attr attr = { 84 .qp_state = IBV_QPS_RTR, 85 .path_mtu = mtu, 86 .dest_qp_num = dest->qpn, 87 .rq_psn = dest->psn, 88 .ah_attr = { 89 .is_global = 0, 90 .dlid = dest->lid, 91 .sl = sl, 92 .src_path_bits = 0, 93 .port_num = port 94 } 95 }; 96 97 if (dest->gid.global.interface_id) { 98 attr.ah_attr.is_global = 1; 99 attr.ah_attr.grh.hop_limit = 1; 100 attr.ah_attr.grh.dgid = dest->gid; 101 attr.ah_attr.grh.sgid_index = sgid_idx; 102 } 103 if (ibv_modify_qp(ctx->qp, &attr, 104 IBV_QP_STATE | 105 IBV_QP_AV | 106 IBV_QP_PATH_MTU | 107 IBV_QP_DEST_QPN | 108 IBV_QP_RQ_PSN)) { 109 fprintf(stderr, "Failed to modify QP to RTR\n"); 110 return 1; 111 } 112 113 attr.qp_state = IBV_QPS_RTS; 114 attr.sq_psn = my_psn; 115 if (ibv_modify_qp(ctx->qp, &attr, 116 IBV_QP_STATE | 117 IBV_QP_SQ_PSN)) { 118 fprintf(stderr, "Failed to modify QP to RTS\n"); 119 return 1; 120 } 121 122 return 0; 123 } 124 125 static struct pingpong_dest *pp_client_exch_dest(const char *servername, int port, 126 const struct pingpong_dest *my_dest) 127 { 128 struct addrinfo *res, *t; 129 struct addrinfo hints = { 130 .ai_family = AF_INET, 131 .ai_socktype = SOCK_STREAM 132 }; 133 char *service; 134 char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; 135 int n; 136 int sockfd = -1; 137 struct pingpong_dest *rem_dest = NULL; 138 char gid[33]; 139 140 if (asprintf(&service, "%d", port) < 0) 141 return NULL; 142 143 n = getaddrinfo(servername, service, &hints, &res); 144 145 if (n < 0) { 146 fprintf(stderr, "%s for %s:%d\n", gai_strerror(n), servername, port); 147 free(service); 148 return NULL; 149 } 150 151 for (t = res; t; t = t->ai_next) { 152 sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); 153 if (sockfd >= 0) { 154 if (!connect(sockfd, t->ai_addr, t->ai_addrlen)) 155 break; 156 close(sockfd); 157 sockfd = -1; 158 } 159 } 160 161 freeaddrinfo_null(res); 162 free(service); 163 164 if (sockfd < 0) { 165 fprintf(stderr, "Couldn't connect to %s:%d\n", servername, port); 166 return NULL; 167 } 168 169 gid_to_wire_gid(&my_dest->gid, gid); 170 sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, 171 my_dest->psn, gid); 172 if (write(sockfd, msg, sizeof msg) != sizeof msg) { 173 fprintf(stderr, "Couldn't send local address\n"); 174 goto out; 175 } 176 177 if (read(sockfd, msg, sizeof msg) != sizeof msg || 178 write(sockfd, "done", sizeof "done") != sizeof "done") { 179 perror("client read/write"); 180 fprintf(stderr, "Couldn't read/write remote address\n"); 181 goto out; 182 } 183 184 185 rem_dest = malloc(sizeof *rem_dest); 186 if (!rem_dest) 187 goto out; 188 189 sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, 190 &rem_dest->psn, gid); 191 wire_gid_to_gid(gid, &rem_dest->gid); 192 193 out: 194 close(sockfd); 195 return rem_dest; 196 } 197 198 static struct pingpong_dest *pp_server_exch_dest(struct pingpong_context *ctx, 199 int ib_port, enum ibv_mtu mtu, 200 int port, int sl, 201 const struct pingpong_dest *my_dest, 202 int sgid_idx) 203 { 204 struct addrinfo *res, *t; 205 struct addrinfo hints = { 206 .ai_flags = AI_PASSIVE, 207 .ai_family = AF_INET, 208 .ai_socktype = SOCK_STREAM 209 }; 210 char *service; 211 char msg[sizeof "0000:000000:000000:00000000000000000000000000000000"]; 212 int n; 213 int sockfd = -1, connfd; 214 struct pingpong_dest *rem_dest = NULL; 215 char gid[33]; 216 217 if (asprintf(&service, "%d", port) < 0) 218 return NULL; 219 220 n = getaddrinfo(NULL, service, &hints, &res); 221 222 if (n < 0) { 223 fprintf(stderr, "%s for port %d\n", gai_strerror(n), port); 224 free(service); 225 return NULL; 226 } 227 228 for (t = res; t; t = t->ai_next) { 229 sockfd = socket(t->ai_family, t->ai_socktype, t->ai_protocol); 230 if (sockfd >= 0) { 231 n = 1; 232 233 setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &n, sizeof n); 234 235 if (!bind(sockfd, t->ai_addr, t->ai_addrlen)) 236 break; 237 close(sockfd); 238 sockfd = -1; 239 } 240 } 241 242 freeaddrinfo_null(res); 243 free(service); 244 245 if (sockfd < 0) { 246 fprintf(stderr, "Couldn't listen to port %d\n", port); 247 return NULL; 248 } 249 250 listen(sockfd, 1); 251 connfd = accept(sockfd, NULL, NULL); 252 close(sockfd); 253 if (connfd < 0) { 254 fprintf(stderr, "accept() failed\n"); 255 return NULL; 256 } 257 258 n = read(connfd, msg, sizeof msg); 259 if (n != sizeof msg) { 260 perror("server read"); 261 fprintf(stderr, "%d/%d: Couldn't read remote address\n", n, (int) sizeof msg); 262 goto out; 263 } 264 265 rem_dest = malloc(sizeof *rem_dest); 266 if (!rem_dest) 267 goto out; 268 269 sscanf(msg, "%x:%x:%x:%s", &rem_dest->lid, &rem_dest->qpn, 270 &rem_dest->psn, gid); 271 wire_gid_to_gid(gid, &rem_dest->gid); 272 273 if (pp_connect_ctx(ctx, ib_port, my_dest->psn, mtu, sl, rem_dest, 274 sgid_idx)) { 275 fprintf(stderr, "Couldn't connect to remote QP\n"); 276 free(rem_dest); 277 rem_dest = NULL; 278 goto out; 279 } 280 281 282 gid_to_wire_gid(&my_dest->gid, gid); 283 sprintf(msg, "%04x:%06x:%06x:%s", my_dest->lid, my_dest->qpn, 284 my_dest->psn, gid); 285 if (write(connfd, msg, sizeof msg) != sizeof msg || 286 read(connfd, msg, sizeof msg) != sizeof "done") { 287 fprintf(stderr, "Couldn't send/recv local address\n"); 288 free(rem_dest); 289 rem_dest = NULL; 290 goto out; 291 } 292 293 out: 294 close(connfd); 295 return rem_dest; 296 } 297 298 static struct pingpong_context *pp_init_ctx(struct ibv_device *ib_dev, int size, 299 int rx_depth, int port, 300 int use_event) 301 { 302 struct pingpong_context *ctx; 303 304 ctx = calloc(1, sizeof *ctx); 305 if (!ctx) 306 return NULL; 307 308 ctx->size = size; 309 ctx->send_flags = IBV_SEND_SIGNALED; 310 ctx->rx_depth = rx_depth; 311 312 ctx->buf = memalign(page_size, size); 313 if (!ctx->buf) { 314 fprintf(stderr, "Couldn't allocate work buf.\n"); 315 goto clean_ctx; 316 } 317 318 /* FIXME memset(ctx->buf, 0, size); */ 319 memset(ctx->buf, 0x7b, size); 320 321 ctx->context = ibv_open_device(ib_dev); 322 if (!ctx->context) { 323 fprintf(stderr, "Couldn't get context for %s\n", 324 ibv_get_device_name(ib_dev)); 325 goto clean_buffer; 326 } 327 328 if (use_event) { 329 ctx->channel = ibv_create_comp_channel(ctx->context); 330 if (!ctx->channel) { 331 fprintf(stderr, "Couldn't create completion channel\n"); 332 goto clean_device; 333 } 334 } else 335 ctx->channel = NULL; 336 337 ctx->pd = ibv_alloc_pd(ctx->context); 338 if (!ctx->pd) { 339 fprintf(stderr, "Couldn't allocate PD\n"); 340 goto clean_comp_channel; 341 } 342 343 ctx->mr = ibv_reg_mr(ctx->pd, ctx->buf, size, IBV_ACCESS_LOCAL_WRITE); 344 if (!ctx->mr) { 345 fprintf(stderr, "Couldn't register MR\n"); 346 goto clean_pd; 347 } 348 349 ctx->cq = ibv_create_cq(ctx->context, rx_depth + 1, NULL, 350 ctx->channel, 0); 351 if (!ctx->cq) { 352 fprintf(stderr, "Couldn't create CQ\n"); 353 goto clean_mr; 354 } 355 356 { 357 struct ibv_qp_attr attr; 358 struct ibv_qp_init_attr init_attr = { 359 .send_cq = ctx->cq, 360 .recv_cq = ctx->cq, 361 .cap = { 362 .max_send_wr = 1, 363 .max_recv_wr = rx_depth, 364 .max_send_sge = 1, 365 .max_recv_sge = 1 366 }, 367 .qp_type = IBV_QPT_UC 368 }; 369 370 ctx->qp = ibv_create_qp(ctx->pd, &init_attr); 371 if (!ctx->qp) { 372 fprintf(stderr, "Couldn't create QP\n"); 373 goto clean_cq; 374 } 375 ibv_query_qp(ctx->qp, &attr, IBV_QP_CAP, &init_attr); 376 if (init_attr.cap.max_inline_data >= size) { 377 ctx->send_flags |= IBV_SEND_INLINE; 378 } 379 } 380 381 { 382 struct ibv_qp_attr attr = { 383 .qp_state = IBV_QPS_INIT, 384 .pkey_index = 0, 385 .port_num = port, 386 .qp_access_flags = 0 387 }; 388 389 if (ibv_modify_qp(ctx->qp, &attr, 390 IBV_QP_STATE | 391 IBV_QP_PKEY_INDEX | 392 IBV_QP_PORT | 393 IBV_QP_ACCESS_FLAGS)) { 394 fprintf(stderr, "Failed to modify QP to INIT\n"); 395 goto clean_qp; 396 } 397 } 398 399 return ctx; 400 401 clean_qp: 402 ibv_destroy_qp(ctx->qp); 403 404 clean_cq: 405 ibv_destroy_cq(ctx->cq); 406 407 clean_mr: 408 ibv_dereg_mr(ctx->mr); 409 410 clean_pd: 411 ibv_dealloc_pd(ctx->pd); 412 413 clean_comp_channel: 414 if (ctx->channel) 415 ibv_destroy_comp_channel(ctx->channel); 416 417 clean_device: 418 ibv_close_device(ctx->context); 419 420 clean_buffer: 421 free(ctx->buf); 422 423 clean_ctx: 424 free(ctx); 425 426 return NULL; 427 } 428 429 static int pp_close_ctx(struct pingpong_context *ctx) 430 { 431 if (ibv_destroy_qp(ctx->qp)) { 432 fprintf(stderr, "Couldn't destroy QP\n"); 433 return 1; 434 } 435 436 if (ibv_destroy_cq(ctx->cq)) { 437 fprintf(stderr, "Couldn't destroy CQ\n"); 438 return 1; 439 } 440 441 if (ibv_dereg_mr(ctx->mr)) { 442 fprintf(stderr, "Couldn't deregister MR\n"); 443 return 1; 444 } 445 446 if (ibv_dealloc_pd(ctx->pd)) { 447 fprintf(stderr, "Couldn't deallocate PD\n"); 448 return 1; 449 } 450 451 if (ctx->channel) { 452 if (ibv_destroy_comp_channel(ctx->channel)) { 453 fprintf(stderr, "Couldn't destroy completion channel\n"); 454 return 1; 455 } 456 } 457 458 if (ibv_close_device(ctx->context)) { 459 fprintf(stderr, "Couldn't release context\n"); 460 return 1; 461 } 462 463 free(ctx->buf); 464 free(ctx); 465 466 return 0; 467 } 468 469 static int pp_post_recv(struct pingpong_context *ctx, int n) 470 { 471 struct ibv_sge list = { 472 .addr = (uintptr_t) ctx->buf, 473 .length = ctx->size, 474 .lkey = ctx->mr->lkey 475 }; 476 struct ibv_recv_wr wr = { 477 .wr_id = PINGPONG_RECV_WRID, 478 .sg_list = &list, 479 .num_sge = 1, 480 }; 481 struct ibv_recv_wr *bad_wr; 482 int i; 483 484 for (i = 0; i < n; ++i) 485 if (ibv_post_recv(ctx->qp, &wr, &bad_wr)) 486 break; 487 488 return i; 489 } 490 491 static int pp_post_send(struct pingpong_context *ctx) 492 { 493 struct ibv_sge list = { 494 .addr = (uintptr_t) ctx->buf, 495 .length = ctx->size, 496 .lkey = ctx->mr->lkey 497 }; 498 struct ibv_send_wr wr = { 499 .wr_id = PINGPONG_SEND_WRID, 500 .sg_list = &list, 501 .num_sge = 1, 502 .opcode = IBV_WR_SEND, 503 .send_flags = ctx->send_flags, 504 }; 505 struct ibv_send_wr *bad_wr; 506 507 return ibv_post_send(ctx->qp, &wr, &bad_wr); 508 } 509 510 static void usage(const char *argv0) 511 { 512 printf("Usage:\n"); 513 printf(" %s start a server and wait for connection\n", argv0); 514 printf(" %s <host> connect to server at <host>\n", argv0); 515 printf("\n"); 516 printf("Options:\n"); 517 printf(" -p, --port=<port> listen on/connect to port <port> (default 18515)\n"); 518 printf(" -d, --ib-dev=<dev> use IB device <dev> (default first device found)\n"); 519 printf(" -i, --ib-port=<port> use port <port> of IB device (default 1)\n"); 520 printf(" -s, --size=<size> size of message to exchange (default 4096)\n"); 521 printf(" -m, --mtu=<size> path MTU (default 1024)\n"); 522 printf(" -r, --rx-depth=<dep> number of receives to post at a time (default 500)\n"); 523 printf(" -n, --iters=<iters> number of exchanges (default 1000)\n"); 524 printf(" -l, --sl=<sl> service level value\n"); 525 printf(" -e, --events sleep on CQ events (default poll)\n"); 526 printf(" -g, --gid-idx=<gid index> local port gid index\n"); 527 } 528 529 int main(int argc, char *argv[]) 530 { 531 struct ibv_device **dev_list; 532 struct ibv_device *ib_dev; 533 struct pingpong_context *ctx; 534 struct pingpong_dest my_dest; 535 struct pingpong_dest *rem_dest; 536 struct timeval start, end; 537 char *ib_devname = NULL; 538 char *servername = NULL; 539 unsigned int port = 18515; 540 int ib_port = 1; 541 unsigned int size = 4096; 542 enum ibv_mtu mtu = IBV_MTU_1024; 543 unsigned int rx_depth = 500; 544 unsigned int iters = 1000; 545 int use_event = 0; 546 int routs; 547 int rcnt, scnt; 548 int num_cq_events = 0; 549 int sl = 0; 550 int gidx = -1; 551 char gid[33]; 552 553 srand48(getpid() * time(NULL)); 554 555 while (1) { 556 int c; 557 558 static struct option long_options[] = { 559 { .name = "port", .has_arg = 1, .val = 'p' }, 560 { .name = "ib-dev", .has_arg = 1, .val = 'd' }, 561 { .name = "ib-port", .has_arg = 1, .val = 'i' }, 562 { .name = "size", .has_arg = 1, .val = 's' }, 563 { .name = "mtu", .has_arg = 1, .val = 'm' }, 564 { .name = "rx-depth", .has_arg = 1, .val = 'r' }, 565 { .name = "iters", .has_arg = 1, .val = 'n' }, 566 { .name = "sl", .has_arg = 1, .val = 'l' }, 567 { .name = "events", .has_arg = 0, .val = 'e' }, 568 { .name = "gid-idx", .has_arg = 1, .val = 'g' }, 569 {} 570 }; 571 572 c = getopt_long(argc, argv, "p:d:i:s:m:r:n:l:eg:", 573 long_options, NULL); 574 if (c == -1) 575 break; 576 577 switch (c) { 578 case 'p': 579 port = strtoul(optarg, NULL, 0); 580 if (port > 65535) { 581 usage(argv[0]); 582 return 1; 583 } 584 break; 585 586 case 'd': 587 ib_devname = strdupa(optarg); 588 break; 589 590 case 'i': 591 ib_port = strtol(optarg, NULL, 0); 592 if (ib_port < 1) { 593 usage(argv[0]); 594 return 1; 595 } 596 break; 597 598 case 's': 599 size = strtoul(optarg, NULL, 0); 600 break; 601 602 case 'm': 603 mtu = pp_mtu_to_enum(strtol(optarg, NULL, 0)); 604 if (mtu == 0) { 605 usage(argv[0]); 606 return 1; 607 } 608 break; 609 610 case 'r': 611 rx_depth = strtoul(optarg, NULL, 0); 612 break; 613 614 case 'n': 615 iters = strtoul(optarg, NULL, 0); 616 break; 617 618 case 'l': 619 sl = strtol(optarg, NULL, 0); 620 break; 621 622 case 'e': 623 ++use_event; 624 break; 625 626 case 'g': 627 gidx = strtol(optarg, NULL, 0); 628 break; 629 630 default: 631 usage(argv[0]); 632 return 1; 633 } 634 } 635 636 if (optind == argc - 1) 637 servername = strdupa(argv[optind]); 638 else if (optind < argc) { 639 usage(argv[0]); 640 return 1; 641 } 642 643 page_size = sysconf(_SC_PAGESIZE); 644 645 dev_list = ibv_get_device_list(NULL); 646 if (!dev_list) { 647 perror("Failed to get IB devices list"); 648 return 1; 649 } 650 651 if (!ib_devname) { 652 ib_dev = *dev_list; 653 if (!ib_dev) { 654 fprintf(stderr, "No IB devices found\n"); 655 return 1; 656 } 657 } else { 658 int i; 659 for (i = 0; dev_list[i]; ++i) 660 if (!strcmp(ibv_get_device_name(dev_list[i]), ib_devname)) 661 break; 662 ib_dev = dev_list[i]; 663 if (!ib_dev) { 664 fprintf(stderr, "IB device %s not found\n", ib_devname); 665 return 1; 666 } 667 } 668 669 ctx = pp_init_ctx(ib_dev, size, rx_depth, ib_port, use_event); 670 if (!ctx) 671 return 1; 672 673 routs = pp_post_recv(ctx, ctx->rx_depth); 674 if (routs < ctx->rx_depth) { 675 fprintf(stderr, "Couldn't post receive (%d)\n", routs); 676 return 1; 677 } 678 679 if (use_event) 680 if (ibv_req_notify_cq(ctx->cq, 0)) { 681 fprintf(stderr, "Couldn't request CQ notification\n"); 682 return 1; 683 } 684 685 686 if (pp_get_port_info(ctx->context, ib_port, &ctx->portinfo)) { 687 fprintf(stderr, "Couldn't get port info\n"); 688 return 1; 689 } 690 691 my_dest.lid = ctx->portinfo.lid; 692 if (ctx->portinfo.link_layer != IBV_LINK_LAYER_ETHERNET && 693 !my_dest.lid) { 694 fprintf(stderr, "Couldn't get local LID\n"); 695 return 1; 696 } 697 698 if (gidx >= 0) { 699 if (ibv_query_gid(ctx->context, ib_port, gidx, &my_dest.gid)) { 700 fprintf(stderr, "can't read sgid of index %d\n", gidx); 701 return 1; 702 } 703 } else 704 memset(&my_dest.gid, 0, sizeof my_dest.gid); 705 706 my_dest.qpn = ctx->qp->qp_num; 707 my_dest.psn = lrand48() & 0xffffff; 708 inet_ntop(AF_INET6, &my_dest.gid, gid, sizeof gid); 709 printf(" local address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", 710 my_dest.lid, my_dest.qpn, my_dest.psn, gid); 711 712 713 if (servername) 714 rem_dest = pp_client_exch_dest(servername, port, &my_dest); 715 else 716 rem_dest = pp_server_exch_dest(ctx, ib_port, mtu, port, sl, 717 &my_dest, gidx); 718 719 if (!rem_dest) 720 return 1; 721 722 inet_ntop(AF_INET6, &rem_dest->gid, gid, sizeof gid); 723 printf(" remote address: LID 0x%04x, QPN 0x%06x, PSN 0x%06x, GID %s\n", 724 rem_dest->lid, rem_dest->qpn, rem_dest->psn, gid); 725 726 if (servername) 727 if (pp_connect_ctx(ctx, ib_port, my_dest.psn, mtu, sl, rem_dest, 728 gidx)) 729 return 1; 730 731 ctx->pending = PINGPONG_RECV_WRID; 732 733 if (servername) { 734 if (pp_post_send(ctx)) { 735 fprintf(stderr, "Couldn't post send\n"); 736 return 1; 737 } 738 ctx->pending |= PINGPONG_SEND_WRID; 739 } 740 741 if (gettimeofday(&start, NULL)) { 742 perror("gettimeofday"); 743 return 1; 744 } 745 746 rcnt = scnt = 0; 747 while (rcnt < iters || scnt < iters) { 748 if (use_event) { 749 struct ibv_cq *ev_cq; 750 void *ev_ctx; 751 752 if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) { 753 fprintf(stderr, "Failed to get cq_event\n"); 754 return 1; 755 } 756 757 ++num_cq_events; 758 759 if (ev_cq != ctx->cq) { 760 fprintf(stderr, "CQ event for unknown CQ %p\n", ev_cq); 761 return 1; 762 } 763 764 if (ibv_req_notify_cq(ctx->cq, 0)) { 765 fprintf(stderr, "Couldn't request CQ notification\n"); 766 return 1; 767 } 768 } 769 770 { 771 struct ibv_wc wc[2]; 772 int ne, i; 773 774 do { 775 ne = ibv_poll_cq(ctx->cq, 2, wc); 776 if (ne < 0) { 777 fprintf(stderr, "poll CQ failed %d\n", ne); 778 return 1; 779 } 780 781 } while (!use_event && ne < 1); 782 783 for (i = 0; i < ne; ++i) { 784 if (wc[i].status != IBV_WC_SUCCESS) { 785 fprintf(stderr, "Failed status %s (%d) for wr_id %d\n", 786 ibv_wc_status_str(wc[i].status), 787 wc[i].status, (int) wc[i].wr_id); 788 return 1; 789 } 790 791 switch ((int) wc[i].wr_id) { 792 case PINGPONG_SEND_WRID: 793 ++scnt; 794 break; 795 796 case PINGPONG_RECV_WRID: 797 if (--routs <= 1) { 798 routs += pp_post_recv(ctx, ctx->rx_depth - routs); 799 if (routs < ctx->rx_depth) { 800 fprintf(stderr, 801 "Couldn't post receive (%d)\n", 802 routs); 803 return 1; 804 } 805 } 806 807 ++rcnt; 808 break; 809 810 default: 811 fprintf(stderr, "Completion for unknown wr_id %d\n", 812 (int) wc[i].wr_id); 813 return 1; 814 } 815 816 ctx->pending &= ~(int) wc[i].wr_id; 817 if (scnt < iters && !ctx->pending) { 818 if (pp_post_send(ctx)) { 819 fprintf(stderr, "Couldn't post send\n"); 820 return 1; 821 } 822 ctx->pending = PINGPONG_RECV_WRID | 823 PINGPONG_SEND_WRID; 824 } 825 } 826 } 827 } 828 829 if (gettimeofday(&end, NULL)) { 830 perror("gettimeofday"); 831 return 1; 832 } 833 834 { 835 float usec = (end.tv_sec - start.tv_sec) * 1000000 + 836 (end.tv_usec - start.tv_usec); 837 long long bytes = (long long) size * iters * 2; 838 839 printf("%lld bytes in %.2f seconds = %.2f Mbit/sec\n", 840 bytes, usec / 1000000., bytes * 8. / usec); 841 printf("%d iters in %.2f seconds = %.2f usec/iter\n", 842 iters, usec / 1000000., usec / iters); 843 } 844 845 ibv_ack_cq_events(ctx->cq, num_cq_events); 846 847 if (pp_close_ctx(ctx)) 848 return 1; 849 850 ibv_free_device_list(dev_list); 851 free(rem_dest); 852 853 return 0; 854 } 855