1*d6b92ffaSHans Petter Selasky /*
2*d6b92ffaSHans Petter Selasky * Copyright (c) 2011-2012 Intel Corporation. All rights reserved.
3*d6b92ffaSHans Petter Selasky * Copyright (c) 2014 Mellanox Technologies LTD. All rights reserved.
4*d6b92ffaSHans Petter Selasky *
5*d6b92ffaSHans Petter Selasky * This software is available to you under the OpenIB.org BSD license
6*d6b92ffaSHans Petter Selasky * below:
7*d6b92ffaSHans Petter Selasky *
8*d6b92ffaSHans Petter Selasky * Redistribution and use in source and binary forms, with or
9*d6b92ffaSHans Petter Selasky * without modification, are permitted provided that the following
10*d6b92ffaSHans Petter Selasky * conditions are met:
11*d6b92ffaSHans Petter Selasky *
12*d6b92ffaSHans Petter Selasky * - Redistributions of source code must retain the above
13*d6b92ffaSHans Petter Selasky * copyright notice, this list of conditions and the following
14*d6b92ffaSHans Petter Selasky * disclaimer.
15*d6b92ffaSHans Petter Selasky *
16*d6b92ffaSHans Petter Selasky * - Redistributions in binary form must reproduce the above
17*d6b92ffaSHans Petter Selasky * copyright notice, this list of conditions and the following
18*d6b92ffaSHans Petter Selasky * disclaimer in the documentation and/or other materials
19*d6b92ffaSHans Petter Selasky * provided with the distribution.
20*d6b92ffaSHans Petter Selasky *
21*d6b92ffaSHans Petter Selasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22*d6b92ffaSHans Petter Selasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23*d6b92ffaSHans Petter Selasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AWV
24*d6b92ffaSHans Petter Selasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
25*d6b92ffaSHans Petter Selasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
26*d6b92ffaSHans Petter Selasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27*d6b92ffaSHans Petter Selasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28*d6b92ffaSHans Petter Selasky * SOFTWARE.
29*d6b92ffaSHans Petter Selasky */
30*d6b92ffaSHans Petter Selasky
31*d6b92ffaSHans Petter Selasky #include <stdio.h>
32*d6b92ffaSHans Petter Selasky #include <stdlib.h>
33*d6b92ffaSHans Petter Selasky #include <string.h>
34*d6b92ffaSHans Petter Selasky #include <strings.h>
35*d6b92ffaSHans Petter Selasky #include <errno.h>
36*d6b92ffaSHans Petter Selasky #include <getopt.h>
37*d6b92ffaSHans Petter Selasky #include <sys/types.h>
38*d6b92ffaSHans Petter Selasky #include <sys/socket.h>
39*d6b92ffaSHans Petter Selasky #include <sys/time.h>
40*d6b92ffaSHans Petter Selasky #include <sys/wait.h>
41*d6b92ffaSHans Petter Selasky #include <netdb.h>
42*d6b92ffaSHans Petter Selasky #include <fcntl.h>
43*d6b92ffaSHans Petter Selasky #include <unistd.h>
44*d6b92ffaSHans Petter Selasky #include <netinet/tcp.h>
45*d6b92ffaSHans Petter Selasky
46*d6b92ffaSHans Petter Selasky #include <rdma/rdma_cma.h>
47*d6b92ffaSHans Petter Selasky #include <rdma/rsocket.h>
48*d6b92ffaSHans Petter Selasky #include <util/compiler.h>
49*d6b92ffaSHans Petter Selasky #include "common.h"
50*d6b92ffaSHans Petter Selasky
51*d6b92ffaSHans Petter Selasky struct test_size_param {
52*d6b92ffaSHans Petter Selasky int size;
53*d6b92ffaSHans Petter Selasky int option;
54*d6b92ffaSHans Petter Selasky };
55*d6b92ffaSHans Petter Selasky
56*d6b92ffaSHans Petter Selasky static struct test_size_param test_size[] = {
57*d6b92ffaSHans Petter Selasky { 1 << 6, 0 },
58*d6b92ffaSHans Petter Selasky { 1 << 7, 1 }, { (1 << 7) + (1 << 6), 1},
59*d6b92ffaSHans Petter Selasky { 1 << 8, 1 }, { (1 << 8) + (1 << 7), 1},
60*d6b92ffaSHans Petter Selasky { 1 << 9, 1 }, { (1 << 9) + (1 << 8), 1},
61*d6b92ffaSHans Petter Selasky { 1 << 10, 1 }, { (1 << 10) + (1 << 9), 1},
62*d6b92ffaSHans Petter Selasky { 1 << 11, 1 }, { (1 << 11) + (1 << 10), 1},
63*d6b92ffaSHans Petter Selasky { 1 << 12, 0 }, { (1 << 12) + (1 << 11), 1},
64*d6b92ffaSHans Petter Selasky { 1 << 13, 1 }, { (1 << 13) + (1 << 12), 1},
65*d6b92ffaSHans Petter Selasky { 1 << 14, 1 }, { (1 << 14) + (1 << 13), 1},
66*d6b92ffaSHans Petter Selasky { 1 << 15, 1 }, { (1 << 15) + (1 << 14), 1},
67*d6b92ffaSHans Petter Selasky { 1 << 16, 0 }, { (1 << 16) + (1 << 15), 1},
68*d6b92ffaSHans Petter Selasky { 1 << 17, 1 }, { (1 << 17) + (1 << 16), 1},
69*d6b92ffaSHans Petter Selasky { 1 << 18, 1 }, { (1 << 18) + (1 << 17), 1},
70*d6b92ffaSHans Petter Selasky { 1 << 19, 1 }, { (1 << 19) + (1 << 18), 1},
71*d6b92ffaSHans Petter Selasky { 1 << 20, 0 }, { (1 << 20) + (1 << 19), 1},
72*d6b92ffaSHans Petter Selasky { 1 << 21, 1 }, { (1 << 21) + (1 << 20), 1},
73*d6b92ffaSHans Petter Selasky { 1 << 22, 1 }, { (1 << 22) + (1 << 21), 1},
74*d6b92ffaSHans Petter Selasky };
75*d6b92ffaSHans Petter Selasky #define TEST_CNT (sizeof test_size / sizeof test_size[0])
76*d6b92ffaSHans Petter Selasky
77*d6b92ffaSHans Petter Selasky static int rs, lrs;
78*d6b92ffaSHans Petter Selasky static int use_async;
79*d6b92ffaSHans Petter Selasky static int use_rgai;
80*d6b92ffaSHans Petter Selasky static int verify;
81*d6b92ffaSHans Petter Selasky static int flags = MSG_DONTWAIT;
82*d6b92ffaSHans Petter Selasky static int poll_timeout = 0;
83*d6b92ffaSHans Petter Selasky static int custom;
84*d6b92ffaSHans Petter Selasky static enum rs_optimization optimization;
85*d6b92ffaSHans Petter Selasky static int size_option;
86*d6b92ffaSHans Petter Selasky static int iterations = 1;
87*d6b92ffaSHans Petter Selasky static int transfer_size = 1000;
88*d6b92ffaSHans Petter Selasky static int transfer_count = 1000;
89*d6b92ffaSHans Petter Selasky static int buffer_size, inline_size = 64;
90*d6b92ffaSHans Petter Selasky static char test_name[10] = "custom";
91*d6b92ffaSHans Petter Selasky static const char *port = "7471";
92*d6b92ffaSHans Petter Selasky static char *dst_addr;
93*d6b92ffaSHans Petter Selasky static char *src_addr;
94*d6b92ffaSHans Petter Selasky static struct timeval start, end;
95*d6b92ffaSHans Petter Selasky static void *buf;
96*d6b92ffaSHans Petter Selasky static volatile uint8_t *poll_byte;
97*d6b92ffaSHans Petter Selasky static struct rdma_addrinfo rai_hints;
98*d6b92ffaSHans Petter Selasky static struct addrinfo ai_hints;
99*d6b92ffaSHans Petter Selasky
show_perf(void)100*d6b92ffaSHans Petter Selasky static void show_perf(void)
101*d6b92ffaSHans Petter Selasky {
102*d6b92ffaSHans Petter Selasky char str[32];
103*d6b92ffaSHans Petter Selasky float usec;
104*d6b92ffaSHans Petter Selasky long long bytes;
105*d6b92ffaSHans Petter Selasky
106*d6b92ffaSHans Petter Selasky usec = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec);
107*d6b92ffaSHans Petter Selasky bytes = (long long) iterations * transfer_count * transfer_size * 2;
108*d6b92ffaSHans Petter Selasky
109*d6b92ffaSHans Petter Selasky /* name size transfers iterations bytes seconds Gb/sec usec/xfer */
110*d6b92ffaSHans Petter Selasky printf("%-10s", test_name);
111*d6b92ffaSHans Petter Selasky size_str(str, sizeof str, transfer_size);
112*d6b92ffaSHans Petter Selasky printf("%-8s", str);
113*d6b92ffaSHans Petter Selasky cnt_str(str, sizeof str, transfer_count);
114*d6b92ffaSHans Petter Selasky printf("%-8s", str);
115*d6b92ffaSHans Petter Selasky cnt_str(str, sizeof str, iterations);
116*d6b92ffaSHans Petter Selasky printf("%-8s", str);
117*d6b92ffaSHans Petter Selasky size_str(str, sizeof str, bytes);
118*d6b92ffaSHans Petter Selasky printf("%-8s", str);
119*d6b92ffaSHans Petter Selasky printf("%8.2fs%10.2f%11.2f\n",
120*d6b92ffaSHans Petter Selasky usec / 1000000., (bytes * 8) / (1000. * usec),
121*d6b92ffaSHans Petter Selasky (usec / iterations) / (transfer_count * 2));
122*d6b92ffaSHans Petter Selasky }
123*d6b92ffaSHans Petter Selasky
init_latency_test(int size)124*d6b92ffaSHans Petter Selasky static void init_latency_test(int size)
125*d6b92ffaSHans Petter Selasky {
126*d6b92ffaSHans Petter Selasky char sstr[5];
127*d6b92ffaSHans Petter Selasky
128*d6b92ffaSHans Petter Selasky size_str(sstr, sizeof sstr, size);
129*d6b92ffaSHans Petter Selasky snprintf(test_name, sizeof test_name, "%s_lat", sstr);
130*d6b92ffaSHans Petter Selasky transfer_count = 1;
131*d6b92ffaSHans Petter Selasky transfer_size = size;
132*d6b92ffaSHans Petter Selasky iterations = size_to_count(transfer_size);
133*d6b92ffaSHans Petter Selasky }
134*d6b92ffaSHans Petter Selasky
init_bandwidth_test(int size)135*d6b92ffaSHans Petter Selasky static void init_bandwidth_test(int size)
136*d6b92ffaSHans Petter Selasky {
137*d6b92ffaSHans Petter Selasky char sstr[5];
138*d6b92ffaSHans Petter Selasky
139*d6b92ffaSHans Petter Selasky size_str(sstr, sizeof sstr, size);
140*d6b92ffaSHans Petter Selasky snprintf(test_name, sizeof test_name, "%s_bw", sstr);
141*d6b92ffaSHans Petter Selasky iterations = 1;
142*d6b92ffaSHans Petter Selasky transfer_size = size;
143*d6b92ffaSHans Petter Selasky transfer_count = size_to_count(transfer_size);
144*d6b92ffaSHans Petter Selasky }
145*d6b92ffaSHans Petter Selasky
send_msg(int size)146*d6b92ffaSHans Petter Selasky static int send_msg(int size)
147*d6b92ffaSHans Petter Selasky {
148*d6b92ffaSHans Petter Selasky struct pollfd fds;
149*d6b92ffaSHans Petter Selasky int offset, ret;
150*d6b92ffaSHans Petter Selasky
151*d6b92ffaSHans Petter Selasky if (use_async) {
152*d6b92ffaSHans Petter Selasky fds.fd = rs;
153*d6b92ffaSHans Petter Selasky fds.events = POLLOUT;
154*d6b92ffaSHans Petter Selasky }
155*d6b92ffaSHans Petter Selasky
156*d6b92ffaSHans Petter Selasky for (offset = 0; offset < size; ) {
157*d6b92ffaSHans Petter Selasky if (use_async) {
158*d6b92ffaSHans Petter Selasky ret = do_poll(&fds, poll_timeout);
159*d6b92ffaSHans Petter Selasky if (ret)
160*d6b92ffaSHans Petter Selasky return ret;
161*d6b92ffaSHans Petter Selasky }
162*d6b92ffaSHans Petter Selasky
163*d6b92ffaSHans Petter Selasky ret = rsend(rs, buf + offset, size - offset, flags);
164*d6b92ffaSHans Petter Selasky if (ret > 0) {
165*d6b92ffaSHans Petter Selasky offset += ret;
166*d6b92ffaSHans Petter Selasky } else if (errno != EWOULDBLOCK && errno != EAGAIN) {
167*d6b92ffaSHans Petter Selasky perror("rsend");
168*d6b92ffaSHans Petter Selasky return ret;
169*d6b92ffaSHans Petter Selasky }
170*d6b92ffaSHans Petter Selasky }
171*d6b92ffaSHans Petter Selasky
172*d6b92ffaSHans Petter Selasky return 0;
173*d6b92ffaSHans Petter Selasky }
174*d6b92ffaSHans Petter Selasky
send_xfer(int size)175*d6b92ffaSHans Petter Selasky static int send_xfer(int size)
176*d6b92ffaSHans Petter Selasky {
177*d6b92ffaSHans Petter Selasky struct pollfd fds;
178*d6b92ffaSHans Petter Selasky int offset, ret;
179*d6b92ffaSHans Petter Selasky
180*d6b92ffaSHans Petter Selasky if (use_async) {
181*d6b92ffaSHans Petter Selasky fds.fd = rs;
182*d6b92ffaSHans Petter Selasky fds.events = POLLOUT;
183*d6b92ffaSHans Petter Selasky }
184*d6b92ffaSHans Petter Selasky
185*d6b92ffaSHans Petter Selasky for (offset = 0; offset < size; ) {
186*d6b92ffaSHans Petter Selasky if (use_async) {
187*d6b92ffaSHans Petter Selasky ret = do_poll(&fds, poll_timeout);
188*d6b92ffaSHans Petter Selasky if (ret)
189*d6b92ffaSHans Petter Selasky return ret;
190*d6b92ffaSHans Petter Selasky }
191*d6b92ffaSHans Petter Selasky
192*d6b92ffaSHans Petter Selasky ret = riowrite(rs, buf + offset, size - offset, offset, flags);
193*d6b92ffaSHans Petter Selasky if (ret > 0) {
194*d6b92ffaSHans Petter Selasky offset += ret;
195*d6b92ffaSHans Petter Selasky } else if (errno != EWOULDBLOCK && errno != EAGAIN) {
196*d6b92ffaSHans Petter Selasky perror("riowrite");
197*d6b92ffaSHans Petter Selasky return ret;
198*d6b92ffaSHans Petter Selasky }
199*d6b92ffaSHans Petter Selasky }
200*d6b92ffaSHans Petter Selasky
201*d6b92ffaSHans Petter Selasky return 0;
202*d6b92ffaSHans Petter Selasky }
203*d6b92ffaSHans Petter Selasky
recv_msg(int size)204*d6b92ffaSHans Petter Selasky static int recv_msg(int size)
205*d6b92ffaSHans Petter Selasky {
206*d6b92ffaSHans Petter Selasky struct pollfd fds;
207*d6b92ffaSHans Petter Selasky int offset, ret;
208*d6b92ffaSHans Petter Selasky
209*d6b92ffaSHans Petter Selasky if (use_async) {
210*d6b92ffaSHans Petter Selasky fds.fd = rs;
211*d6b92ffaSHans Petter Selasky fds.events = POLLIN;
212*d6b92ffaSHans Petter Selasky }
213*d6b92ffaSHans Petter Selasky
214*d6b92ffaSHans Petter Selasky for (offset = 0; offset < size; ) {
215*d6b92ffaSHans Petter Selasky if (use_async) {
216*d6b92ffaSHans Petter Selasky ret = do_poll(&fds, poll_timeout);
217*d6b92ffaSHans Petter Selasky if (ret)
218*d6b92ffaSHans Petter Selasky return ret;
219*d6b92ffaSHans Petter Selasky }
220*d6b92ffaSHans Petter Selasky
221*d6b92ffaSHans Petter Selasky ret = rrecv(rs, buf + offset, size - offset, flags);
222*d6b92ffaSHans Petter Selasky if (ret > 0) {
223*d6b92ffaSHans Petter Selasky offset += ret;
224*d6b92ffaSHans Petter Selasky } else if (errno != EWOULDBLOCK && errno != EAGAIN) {
225*d6b92ffaSHans Petter Selasky perror("rrecv");
226*d6b92ffaSHans Petter Selasky return ret;
227*d6b92ffaSHans Petter Selasky }
228*d6b92ffaSHans Petter Selasky }
229*d6b92ffaSHans Petter Selasky
230*d6b92ffaSHans Petter Selasky return 0;
231*d6b92ffaSHans Petter Selasky }
232*d6b92ffaSHans Petter Selasky
recv_xfer(int size,uint8_t marker)233*d6b92ffaSHans Petter Selasky static int recv_xfer(int size, uint8_t marker)
234*d6b92ffaSHans Petter Selasky {
235*d6b92ffaSHans Petter Selasky int ret;
236*d6b92ffaSHans Petter Selasky
237*d6b92ffaSHans Petter Selasky while (*poll_byte != marker)
238*d6b92ffaSHans Petter Selasky ;
239*d6b92ffaSHans Petter Selasky
240*d6b92ffaSHans Petter Selasky if (verify) {
241*d6b92ffaSHans Petter Selasky ret = verify_buf(buf, size - 1);
242*d6b92ffaSHans Petter Selasky if (ret)
243*d6b92ffaSHans Petter Selasky return ret;
244*d6b92ffaSHans Petter Selasky }
245*d6b92ffaSHans Petter Selasky
246*d6b92ffaSHans Petter Selasky return 0;
247*d6b92ffaSHans Petter Selasky }
248*d6b92ffaSHans Petter Selasky
sync_test(void)249*d6b92ffaSHans Petter Selasky static int sync_test(void)
250*d6b92ffaSHans Petter Selasky {
251*d6b92ffaSHans Petter Selasky int ret;
252*d6b92ffaSHans Petter Selasky
253*d6b92ffaSHans Petter Selasky ret = dst_addr ? send_msg(16) : recv_msg(16);
254*d6b92ffaSHans Petter Selasky if (ret)
255*d6b92ffaSHans Petter Selasky return ret;
256*d6b92ffaSHans Petter Selasky
257*d6b92ffaSHans Petter Selasky return dst_addr ? recv_msg(16) : send_msg(16);
258*d6b92ffaSHans Petter Selasky }
259*d6b92ffaSHans Petter Selasky
run_test(void)260*d6b92ffaSHans Petter Selasky static int run_test(void)
261*d6b92ffaSHans Petter Selasky {
262*d6b92ffaSHans Petter Selasky int ret, i, t;
263*d6b92ffaSHans Petter Selasky off_t offset;
264*d6b92ffaSHans Petter Selasky uint8_t marker = 0;
265*d6b92ffaSHans Petter Selasky
266*d6b92ffaSHans Petter Selasky poll_byte = buf + transfer_size - 1;
267*d6b92ffaSHans Petter Selasky *poll_byte = -1;
268*d6b92ffaSHans Petter Selasky offset = riomap(rs, buf, transfer_size, PROT_WRITE, 0, 0);
269*d6b92ffaSHans Petter Selasky if (offset == -1) {
270*d6b92ffaSHans Petter Selasky perror("riomap");
271*d6b92ffaSHans Petter Selasky ret = -1;
272*d6b92ffaSHans Petter Selasky goto out;
273*d6b92ffaSHans Petter Selasky }
274*d6b92ffaSHans Petter Selasky ret = sync_test();
275*d6b92ffaSHans Petter Selasky if (ret)
276*d6b92ffaSHans Petter Selasky goto out;
277*d6b92ffaSHans Petter Selasky
278*d6b92ffaSHans Petter Selasky gettimeofday(&start, NULL);
279*d6b92ffaSHans Petter Selasky for (i = 0; i < iterations; i++) {
280*d6b92ffaSHans Petter Selasky if (dst_addr) {
281*d6b92ffaSHans Petter Selasky for (t = 0; t < transfer_count - 1; t++) {
282*d6b92ffaSHans Petter Selasky ret = send_xfer(transfer_size);
283*d6b92ffaSHans Petter Selasky if (ret)
284*d6b92ffaSHans Petter Selasky goto out;
285*d6b92ffaSHans Petter Selasky }
286*d6b92ffaSHans Petter Selasky *poll_byte = (uint8_t) marker++;
287*d6b92ffaSHans Petter Selasky if (verify)
288*d6b92ffaSHans Petter Selasky format_buf(buf, transfer_size - 1);
289*d6b92ffaSHans Petter Selasky ret = send_xfer(transfer_size);
290*d6b92ffaSHans Petter Selasky if (ret)
291*d6b92ffaSHans Petter Selasky goto out;
292*d6b92ffaSHans Petter Selasky
293*d6b92ffaSHans Petter Selasky ret = recv_xfer(transfer_size, marker++);
294*d6b92ffaSHans Petter Selasky } else {
295*d6b92ffaSHans Petter Selasky ret = recv_xfer(transfer_size, marker++);
296*d6b92ffaSHans Petter Selasky if (ret)
297*d6b92ffaSHans Petter Selasky goto out;
298*d6b92ffaSHans Petter Selasky
299*d6b92ffaSHans Petter Selasky for (t = 0; t < transfer_count - 1; t++) {
300*d6b92ffaSHans Petter Selasky ret = send_xfer(transfer_size);
301*d6b92ffaSHans Petter Selasky if (ret)
302*d6b92ffaSHans Petter Selasky goto out;
303*d6b92ffaSHans Petter Selasky }
304*d6b92ffaSHans Petter Selasky *poll_byte = (uint8_t) marker++;
305*d6b92ffaSHans Petter Selasky if (verify)
306*d6b92ffaSHans Petter Selasky format_buf(buf, transfer_size - 1);
307*d6b92ffaSHans Petter Selasky ret = send_xfer(transfer_size);
308*d6b92ffaSHans Petter Selasky }
309*d6b92ffaSHans Petter Selasky if (ret)
310*d6b92ffaSHans Petter Selasky goto out;
311*d6b92ffaSHans Petter Selasky }
312*d6b92ffaSHans Petter Selasky gettimeofday(&end, NULL);
313*d6b92ffaSHans Petter Selasky show_perf();
314*d6b92ffaSHans Petter Selasky ret = riounmap(rs, buf, transfer_size);
315*d6b92ffaSHans Petter Selasky
316*d6b92ffaSHans Petter Selasky out:
317*d6b92ffaSHans Petter Selasky return ret;
318*d6b92ffaSHans Petter Selasky }
319*d6b92ffaSHans Petter Selasky
set_options(int fd)320*d6b92ffaSHans Petter Selasky static void set_options(int fd)
321*d6b92ffaSHans Petter Selasky {
322*d6b92ffaSHans Petter Selasky int val;
323*d6b92ffaSHans Petter Selasky
324*d6b92ffaSHans Petter Selasky if (buffer_size) {
325*d6b92ffaSHans Petter Selasky rsetsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void *) &buffer_size,
326*d6b92ffaSHans Petter Selasky sizeof buffer_size);
327*d6b92ffaSHans Petter Selasky rsetsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *) &buffer_size,
328*d6b92ffaSHans Petter Selasky sizeof buffer_size);
329*d6b92ffaSHans Petter Selasky } else {
330*d6b92ffaSHans Petter Selasky val = 1 << 19;
331*d6b92ffaSHans Petter Selasky rsetsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void *) &val, sizeof val);
332*d6b92ffaSHans Petter Selasky rsetsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void *) &val, sizeof val);
333*d6b92ffaSHans Petter Selasky }
334*d6b92ffaSHans Petter Selasky
335*d6b92ffaSHans Petter Selasky val = 1;
336*d6b92ffaSHans Petter Selasky rsetsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *) &val, sizeof(val));
337*d6b92ffaSHans Petter Selasky rsetsockopt(fd, SOL_RDMA, RDMA_IOMAPSIZE, (void *) &val, sizeof val);
338*d6b92ffaSHans Petter Selasky
339*d6b92ffaSHans Petter Selasky if (flags & MSG_DONTWAIT)
340*d6b92ffaSHans Petter Selasky rfcntl(fd, F_SETFL, O_NONBLOCK);
341*d6b92ffaSHans Petter Selasky
342*d6b92ffaSHans Petter Selasky /* Inline size based on experimental data */
343*d6b92ffaSHans Petter Selasky if (optimization == opt_latency) {
344*d6b92ffaSHans Petter Selasky rsetsockopt(fd, SOL_RDMA, RDMA_INLINE, &inline_size,
345*d6b92ffaSHans Petter Selasky sizeof inline_size);
346*d6b92ffaSHans Petter Selasky } else if (optimization == opt_bandwidth) {
347*d6b92ffaSHans Petter Selasky val = 0;
348*d6b92ffaSHans Petter Selasky rsetsockopt(fd, SOL_RDMA, RDMA_INLINE, &val, sizeof val);
349*d6b92ffaSHans Petter Selasky }
350*d6b92ffaSHans Petter Selasky }
351*d6b92ffaSHans Petter Selasky
server_listen(void)352*d6b92ffaSHans Petter Selasky static int server_listen(void)
353*d6b92ffaSHans Petter Selasky {
354*d6b92ffaSHans Petter Selasky struct rdma_addrinfo *rai = NULL;
355*d6b92ffaSHans Petter Selasky struct addrinfo *ai;
356*d6b92ffaSHans Petter Selasky int val, ret;
357*d6b92ffaSHans Petter Selasky
358*d6b92ffaSHans Petter Selasky if (use_rgai) {
359*d6b92ffaSHans Petter Selasky rai_hints.ai_flags |= RAI_PASSIVE;
360*d6b92ffaSHans Petter Selasky ret = rdma_getaddrinfo(src_addr, port, &rai_hints, &rai);
361*d6b92ffaSHans Petter Selasky } else {
362*d6b92ffaSHans Petter Selasky ai_hints.ai_flags |= AI_PASSIVE;
363*d6b92ffaSHans Petter Selasky ret = getaddrinfo(src_addr, port, &ai_hints, &ai);
364*d6b92ffaSHans Petter Selasky }
365*d6b92ffaSHans Petter Selasky if (ret) {
366*d6b92ffaSHans Petter Selasky printf("getaddrinfo: %s\n", gai_strerror(ret));
367*d6b92ffaSHans Petter Selasky return ret;
368*d6b92ffaSHans Petter Selasky }
369*d6b92ffaSHans Petter Selasky
370*d6b92ffaSHans Petter Selasky lrs = rai ? rsocket(rai->ai_family, SOCK_STREAM, 0) :
371*d6b92ffaSHans Petter Selasky rsocket(ai->ai_family, SOCK_STREAM, 0);
372*d6b92ffaSHans Petter Selasky if (lrs < 0) {
373*d6b92ffaSHans Petter Selasky perror("rsocket");
374*d6b92ffaSHans Petter Selasky ret = lrs;
375*d6b92ffaSHans Petter Selasky goto free;
376*d6b92ffaSHans Petter Selasky }
377*d6b92ffaSHans Petter Selasky
378*d6b92ffaSHans Petter Selasky val = 1;
379*d6b92ffaSHans Petter Selasky ret = rsetsockopt(lrs, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val);
380*d6b92ffaSHans Petter Selasky if (ret) {
381*d6b92ffaSHans Petter Selasky perror("rsetsockopt SO_REUSEADDR");
382*d6b92ffaSHans Petter Selasky goto close;
383*d6b92ffaSHans Petter Selasky }
384*d6b92ffaSHans Petter Selasky
385*d6b92ffaSHans Petter Selasky ret = rai ? rbind(lrs, rai->ai_src_addr, rai->ai_src_len) :
386*d6b92ffaSHans Petter Selasky rbind(lrs, ai->ai_addr, ai->ai_addrlen);
387*d6b92ffaSHans Petter Selasky if (ret) {
388*d6b92ffaSHans Petter Selasky perror("rbind");
389*d6b92ffaSHans Petter Selasky goto close;
390*d6b92ffaSHans Petter Selasky }
391*d6b92ffaSHans Petter Selasky
392*d6b92ffaSHans Petter Selasky ret = rlisten(lrs, 1);
393*d6b92ffaSHans Petter Selasky if (ret)
394*d6b92ffaSHans Petter Selasky perror("rlisten");
395*d6b92ffaSHans Petter Selasky
396*d6b92ffaSHans Petter Selasky close:
397*d6b92ffaSHans Petter Selasky if (ret)
398*d6b92ffaSHans Petter Selasky rclose(lrs);
399*d6b92ffaSHans Petter Selasky free:
400*d6b92ffaSHans Petter Selasky if (rai)
401*d6b92ffaSHans Petter Selasky rdma_freeaddrinfo(rai);
402*d6b92ffaSHans Petter Selasky else
403*d6b92ffaSHans Petter Selasky freeaddrinfo(ai);
404*d6b92ffaSHans Petter Selasky return ret;
405*d6b92ffaSHans Petter Selasky }
406*d6b92ffaSHans Petter Selasky
server_connect(void)407*d6b92ffaSHans Petter Selasky static int server_connect(void)
408*d6b92ffaSHans Petter Selasky {
409*d6b92ffaSHans Petter Selasky struct pollfd fds;
410*d6b92ffaSHans Petter Selasky int ret = 0;
411*d6b92ffaSHans Petter Selasky
412*d6b92ffaSHans Petter Selasky set_options(lrs);
413*d6b92ffaSHans Petter Selasky do {
414*d6b92ffaSHans Petter Selasky if (use_async) {
415*d6b92ffaSHans Petter Selasky fds.fd = lrs;
416*d6b92ffaSHans Petter Selasky fds.events = POLLIN;
417*d6b92ffaSHans Petter Selasky
418*d6b92ffaSHans Petter Selasky ret = do_poll(&fds, poll_timeout);
419*d6b92ffaSHans Petter Selasky if (ret) {
420*d6b92ffaSHans Petter Selasky perror("rpoll");
421*d6b92ffaSHans Petter Selasky return ret;
422*d6b92ffaSHans Petter Selasky }
423*d6b92ffaSHans Petter Selasky }
424*d6b92ffaSHans Petter Selasky
425*d6b92ffaSHans Petter Selasky rs = raccept(lrs, NULL, NULL);
426*d6b92ffaSHans Petter Selasky } while (rs < 0 && (errno == EAGAIN || errno == EWOULDBLOCK));
427*d6b92ffaSHans Petter Selasky if (rs < 0) {
428*d6b92ffaSHans Petter Selasky perror("raccept");
429*d6b92ffaSHans Petter Selasky return rs;
430*d6b92ffaSHans Petter Selasky }
431*d6b92ffaSHans Petter Selasky
432*d6b92ffaSHans Petter Selasky set_options(rs);
433*d6b92ffaSHans Petter Selasky return ret;
434*d6b92ffaSHans Petter Selasky }
435*d6b92ffaSHans Petter Selasky
client_connect(void)436*d6b92ffaSHans Petter Selasky static int client_connect(void)
437*d6b92ffaSHans Petter Selasky {
438*d6b92ffaSHans Petter Selasky struct rdma_addrinfo *rai = NULL;
439*d6b92ffaSHans Petter Selasky struct addrinfo *ai;
440*d6b92ffaSHans Petter Selasky struct pollfd fds;
441*d6b92ffaSHans Petter Selasky int ret, err;
442*d6b92ffaSHans Petter Selasky socklen_t len;
443*d6b92ffaSHans Petter Selasky
444*d6b92ffaSHans Petter Selasky ret = use_rgai ? rdma_getaddrinfo(dst_addr, port, &rai_hints, &rai) :
445*d6b92ffaSHans Petter Selasky getaddrinfo(dst_addr, port, &ai_hints, &ai);
446*d6b92ffaSHans Petter Selasky if (ret) {
447*d6b92ffaSHans Petter Selasky printf("getaddrinfo: %s\n", gai_strerror(ret));
448*d6b92ffaSHans Petter Selasky return ret;
449*d6b92ffaSHans Petter Selasky }
450*d6b92ffaSHans Petter Selasky
451*d6b92ffaSHans Petter Selasky rs = rai ? rsocket(rai->ai_family, SOCK_STREAM, 0) :
452*d6b92ffaSHans Petter Selasky rsocket(ai->ai_family, SOCK_STREAM, 0);
453*d6b92ffaSHans Petter Selasky if (rs < 0) {
454*d6b92ffaSHans Petter Selasky perror("rsocket");
455*d6b92ffaSHans Petter Selasky ret = rs;
456*d6b92ffaSHans Petter Selasky goto free;
457*d6b92ffaSHans Petter Selasky }
458*d6b92ffaSHans Petter Selasky
459*d6b92ffaSHans Petter Selasky set_options(rs);
460*d6b92ffaSHans Petter Selasky /* TODO: bind client to src_addr */
461*d6b92ffaSHans Petter Selasky
462*d6b92ffaSHans Petter Selasky ret = rai ? rconnect(rs, rai->ai_dst_addr, rai->ai_dst_len) :
463*d6b92ffaSHans Petter Selasky rconnect(rs, ai->ai_addr, ai->ai_addrlen);
464*d6b92ffaSHans Petter Selasky if (ret && (errno != EINPROGRESS)) {
465*d6b92ffaSHans Petter Selasky perror("rconnect");
466*d6b92ffaSHans Petter Selasky goto close;
467*d6b92ffaSHans Petter Selasky }
468*d6b92ffaSHans Petter Selasky
469*d6b92ffaSHans Petter Selasky if (ret && (errno == EINPROGRESS)) {
470*d6b92ffaSHans Petter Selasky fds.fd = rs;
471*d6b92ffaSHans Petter Selasky fds.events = POLLOUT;
472*d6b92ffaSHans Petter Selasky ret = do_poll(&fds, poll_timeout);
473*d6b92ffaSHans Petter Selasky if (ret) {
474*d6b92ffaSHans Petter Selasky perror("rpoll");
475*d6b92ffaSHans Petter Selasky goto close;
476*d6b92ffaSHans Petter Selasky }
477*d6b92ffaSHans Petter Selasky
478*d6b92ffaSHans Petter Selasky len = sizeof err;
479*d6b92ffaSHans Petter Selasky ret = rgetsockopt(rs, SOL_SOCKET, SO_ERROR, &err, &len);
480*d6b92ffaSHans Petter Selasky if (ret)
481*d6b92ffaSHans Petter Selasky goto close;
482*d6b92ffaSHans Petter Selasky if (err) {
483*d6b92ffaSHans Petter Selasky ret = -1;
484*d6b92ffaSHans Petter Selasky errno = err;
485*d6b92ffaSHans Petter Selasky perror("async rconnect");
486*d6b92ffaSHans Petter Selasky }
487*d6b92ffaSHans Petter Selasky }
488*d6b92ffaSHans Petter Selasky
489*d6b92ffaSHans Petter Selasky close:
490*d6b92ffaSHans Petter Selasky if (ret)
491*d6b92ffaSHans Petter Selasky rclose(rs);
492*d6b92ffaSHans Petter Selasky free:
493*d6b92ffaSHans Petter Selasky if (rai)
494*d6b92ffaSHans Petter Selasky rdma_freeaddrinfo(rai);
495*d6b92ffaSHans Petter Selasky else
496*d6b92ffaSHans Petter Selasky freeaddrinfo(ai);
497*d6b92ffaSHans Petter Selasky return ret;
498*d6b92ffaSHans Petter Selasky }
499*d6b92ffaSHans Petter Selasky
run(void)500*d6b92ffaSHans Petter Selasky static int run(void)
501*d6b92ffaSHans Petter Selasky {
502*d6b92ffaSHans Petter Selasky int i, ret = 0;
503*d6b92ffaSHans Petter Selasky
504*d6b92ffaSHans Petter Selasky buf = malloc(!custom ? test_size[TEST_CNT - 1].size : transfer_size);
505*d6b92ffaSHans Petter Selasky if (!buf) {
506*d6b92ffaSHans Petter Selasky perror("malloc");
507*d6b92ffaSHans Petter Selasky return -1;
508*d6b92ffaSHans Petter Selasky }
509*d6b92ffaSHans Petter Selasky
510*d6b92ffaSHans Petter Selasky if (!dst_addr) {
511*d6b92ffaSHans Petter Selasky ret = server_listen();
512*d6b92ffaSHans Petter Selasky if (ret)
513*d6b92ffaSHans Petter Selasky goto free;
514*d6b92ffaSHans Petter Selasky }
515*d6b92ffaSHans Petter Selasky
516*d6b92ffaSHans Petter Selasky printf("%-10s%-8s%-8s%-8s%-8s%8s %10s%13s\n",
517*d6b92ffaSHans Petter Selasky "name", "bytes", "xfers", "iters", "total", "time", "Gb/sec", "usec/xfer");
518*d6b92ffaSHans Petter Selasky if (!custom) {
519*d6b92ffaSHans Petter Selasky optimization = opt_latency;
520*d6b92ffaSHans Petter Selasky ret = dst_addr ? client_connect() : server_connect();
521*d6b92ffaSHans Petter Selasky if (ret)
522*d6b92ffaSHans Petter Selasky goto free;
523*d6b92ffaSHans Petter Selasky
524*d6b92ffaSHans Petter Selasky for (i = 0; i < TEST_CNT; i++) {
525*d6b92ffaSHans Petter Selasky if (test_size[i].option > size_option)
526*d6b92ffaSHans Petter Selasky continue;
527*d6b92ffaSHans Petter Selasky init_latency_test(test_size[i].size);
528*d6b92ffaSHans Petter Selasky run_test();
529*d6b92ffaSHans Petter Selasky }
530*d6b92ffaSHans Petter Selasky rshutdown(rs, SHUT_RDWR);
531*d6b92ffaSHans Petter Selasky rclose(rs);
532*d6b92ffaSHans Petter Selasky
533*d6b92ffaSHans Petter Selasky optimization = opt_bandwidth;
534*d6b92ffaSHans Petter Selasky ret = dst_addr ? client_connect() : server_connect();
535*d6b92ffaSHans Petter Selasky if (ret)
536*d6b92ffaSHans Petter Selasky goto free;
537*d6b92ffaSHans Petter Selasky for (i = 0; i < TEST_CNT; i++) {
538*d6b92ffaSHans Petter Selasky if (test_size[i].option > size_option)
539*d6b92ffaSHans Petter Selasky continue;
540*d6b92ffaSHans Petter Selasky init_bandwidth_test(test_size[i].size);
541*d6b92ffaSHans Petter Selasky run_test();
542*d6b92ffaSHans Petter Selasky }
543*d6b92ffaSHans Petter Selasky } else {
544*d6b92ffaSHans Petter Selasky ret = dst_addr ? client_connect() : server_connect();
545*d6b92ffaSHans Petter Selasky if (ret)
546*d6b92ffaSHans Petter Selasky goto free;
547*d6b92ffaSHans Petter Selasky
548*d6b92ffaSHans Petter Selasky ret = run_test();
549*d6b92ffaSHans Petter Selasky }
550*d6b92ffaSHans Petter Selasky
551*d6b92ffaSHans Petter Selasky rshutdown(rs, SHUT_RDWR);
552*d6b92ffaSHans Petter Selasky rclose(rs);
553*d6b92ffaSHans Petter Selasky free:
554*d6b92ffaSHans Petter Selasky free(buf);
555*d6b92ffaSHans Petter Selasky return ret;
556*d6b92ffaSHans Petter Selasky }
557*d6b92ffaSHans Petter Selasky
set_test_opt(const char * arg)558*d6b92ffaSHans Petter Selasky static int set_test_opt(const char *arg)
559*d6b92ffaSHans Petter Selasky {
560*d6b92ffaSHans Petter Selasky if (strlen(arg) == 1) {
561*d6b92ffaSHans Petter Selasky switch (arg[0]) {
562*d6b92ffaSHans Petter Selasky case 'a':
563*d6b92ffaSHans Petter Selasky use_async = 1;
564*d6b92ffaSHans Petter Selasky break;
565*d6b92ffaSHans Petter Selasky case 'b':
566*d6b92ffaSHans Petter Selasky flags = (flags & ~MSG_DONTWAIT) | MSG_WAITALL;
567*d6b92ffaSHans Petter Selasky break;
568*d6b92ffaSHans Petter Selasky case 'n':
569*d6b92ffaSHans Petter Selasky flags |= MSG_DONTWAIT;
570*d6b92ffaSHans Petter Selasky break;
571*d6b92ffaSHans Petter Selasky case 'v':
572*d6b92ffaSHans Petter Selasky verify = 1;
573*d6b92ffaSHans Petter Selasky break;
574*d6b92ffaSHans Petter Selasky default:
575*d6b92ffaSHans Petter Selasky return -1;
576*d6b92ffaSHans Petter Selasky }
577*d6b92ffaSHans Petter Selasky } else {
578*d6b92ffaSHans Petter Selasky if (!strncasecmp("async", arg, 5)) {
579*d6b92ffaSHans Petter Selasky use_async = 1;
580*d6b92ffaSHans Petter Selasky } else if (!strncasecmp("block", arg, 5)) {
581*d6b92ffaSHans Petter Selasky flags = (flags & ~MSG_DONTWAIT) | MSG_WAITALL;
582*d6b92ffaSHans Petter Selasky } else if (!strncasecmp("nonblock", arg, 8)) {
583*d6b92ffaSHans Petter Selasky flags |= MSG_DONTWAIT;
584*d6b92ffaSHans Petter Selasky } else if (!strncasecmp("verify", arg, 6)) {
585*d6b92ffaSHans Petter Selasky verify = 1;
586*d6b92ffaSHans Petter Selasky } else {
587*d6b92ffaSHans Petter Selasky return -1;
588*d6b92ffaSHans Petter Selasky }
589*d6b92ffaSHans Petter Selasky }
590*d6b92ffaSHans Petter Selasky return 0;
591*d6b92ffaSHans Petter Selasky }
592*d6b92ffaSHans Petter Selasky
main(int argc,char ** argv)593*d6b92ffaSHans Petter Selasky int main(int argc, char **argv)
594*d6b92ffaSHans Petter Selasky {
595*d6b92ffaSHans Petter Selasky int op, ret;
596*d6b92ffaSHans Petter Selasky
597*d6b92ffaSHans Petter Selasky ai_hints.ai_socktype = SOCK_STREAM;
598*d6b92ffaSHans Petter Selasky rai_hints.ai_port_space = RDMA_PS_TCP;
599*d6b92ffaSHans Petter Selasky while ((op = getopt(argc, argv, "s:b:f:B:i:I:C:S:p:T:")) != -1) {
600*d6b92ffaSHans Petter Selasky switch (op) {
601*d6b92ffaSHans Petter Selasky case 's':
602*d6b92ffaSHans Petter Selasky dst_addr = optarg;
603*d6b92ffaSHans Petter Selasky break;
604*d6b92ffaSHans Petter Selasky case 'b':
605*d6b92ffaSHans Petter Selasky src_addr = optarg;
606*d6b92ffaSHans Petter Selasky break;
607*d6b92ffaSHans Petter Selasky case 'f':
608*d6b92ffaSHans Petter Selasky if (!strncasecmp("ip", optarg, 2)) {
609*d6b92ffaSHans Petter Selasky ai_hints.ai_flags = AI_NUMERICHOST;
610*d6b92ffaSHans Petter Selasky } else if (!strncasecmp("gid", optarg, 3)) {
611*d6b92ffaSHans Petter Selasky rai_hints.ai_flags = RAI_NUMERICHOST | RAI_FAMILY;
612*d6b92ffaSHans Petter Selasky rai_hints.ai_family = AF_IB;
613*d6b92ffaSHans Petter Selasky use_rgai = 1;
614*d6b92ffaSHans Petter Selasky } else {
615*d6b92ffaSHans Petter Selasky fprintf(stderr, "Warning: unknown address format\n");
616*d6b92ffaSHans Petter Selasky }
617*d6b92ffaSHans Petter Selasky break;
618*d6b92ffaSHans Petter Selasky case 'B':
619*d6b92ffaSHans Petter Selasky buffer_size = atoi(optarg);
620*d6b92ffaSHans Petter Selasky break;
621*d6b92ffaSHans Petter Selasky case 'i':
622*d6b92ffaSHans Petter Selasky inline_size = atoi(optarg);
623*d6b92ffaSHans Petter Selasky break;
624*d6b92ffaSHans Petter Selasky case 'I':
625*d6b92ffaSHans Petter Selasky custom = 1;
626*d6b92ffaSHans Petter Selasky iterations = atoi(optarg);
627*d6b92ffaSHans Petter Selasky break;
628*d6b92ffaSHans Petter Selasky case 'C':
629*d6b92ffaSHans Petter Selasky custom = 1;
630*d6b92ffaSHans Petter Selasky transfer_count = atoi(optarg);
631*d6b92ffaSHans Petter Selasky break;
632*d6b92ffaSHans Petter Selasky case 'S':
633*d6b92ffaSHans Petter Selasky if (!strncasecmp("all", optarg, 3)) {
634*d6b92ffaSHans Petter Selasky size_option = 1;
635*d6b92ffaSHans Petter Selasky } else {
636*d6b92ffaSHans Petter Selasky custom = 1;
637*d6b92ffaSHans Petter Selasky transfer_size = atoi(optarg);
638*d6b92ffaSHans Petter Selasky }
639*d6b92ffaSHans Petter Selasky break;
640*d6b92ffaSHans Petter Selasky case 'p':
641*d6b92ffaSHans Petter Selasky port = optarg;
642*d6b92ffaSHans Petter Selasky break;
643*d6b92ffaSHans Petter Selasky case 'T':
644*d6b92ffaSHans Petter Selasky if (!set_test_opt(optarg))
645*d6b92ffaSHans Petter Selasky break;
646*d6b92ffaSHans Petter Selasky /* invalid option - fall through */
647*d6b92ffaSHans Petter Selasky SWITCH_FALLTHROUGH;
648*d6b92ffaSHans Petter Selasky default:
649*d6b92ffaSHans Petter Selasky printf("usage: %s\n", argv[0]);
650*d6b92ffaSHans Petter Selasky printf("\t[-s server_address]\n");
651*d6b92ffaSHans Petter Selasky printf("\t[-b bind_address]\n");
652*d6b92ffaSHans Petter Selasky printf("\t[-f address_format]\n");
653*d6b92ffaSHans Petter Selasky printf("\t name, ip, ipv6, or gid\n");
654*d6b92ffaSHans Petter Selasky printf("\t[-B buffer_size]\n");
655*d6b92ffaSHans Petter Selasky printf("\t[-i inline_size]\n");
656*d6b92ffaSHans Petter Selasky printf("\t[-I iterations]\n");
657*d6b92ffaSHans Petter Selasky printf("\t[-C transfer_count]\n");
658*d6b92ffaSHans Petter Selasky printf("\t[-S transfer_size or all]\n");
659*d6b92ffaSHans Petter Selasky printf("\t[-p port_number]\n");
660*d6b92ffaSHans Petter Selasky printf("\t[-T test_option]\n");
661*d6b92ffaSHans Petter Selasky printf("\t a|async - asynchronous operation (use poll)\n");
662*d6b92ffaSHans Petter Selasky printf("\t b|blocking - use blocking calls\n");
663*d6b92ffaSHans Petter Selasky printf("\t n|nonblocking - use nonblocking calls\n");
664*d6b92ffaSHans Petter Selasky printf("\t v|verify - verify data\n");
665*d6b92ffaSHans Petter Selasky exit(1);
666*d6b92ffaSHans Petter Selasky }
667*d6b92ffaSHans Petter Selasky }
668*d6b92ffaSHans Petter Selasky
669*d6b92ffaSHans Petter Selasky if (!(flags & MSG_DONTWAIT))
670*d6b92ffaSHans Petter Selasky poll_timeout = -1;
671*d6b92ffaSHans Petter Selasky
672*d6b92ffaSHans Petter Selasky ret = run();
673*d6b92ffaSHans Petter Selasky return ret;
674*d6b92ffaSHans Petter Selasky }
675