[TOOLS] fix send_bw test for UD.
[mirror/winof/.git] / tools / perftests / user / send_lat / send_lat.c
1 /*
2  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
3  * Copyright (c) 2005 Mellanox Technologies Ltd.  All rights reserved.
4  * Copyright (c) 2005 Hewlett Packard, Inc (Grant Grundler)
5  *
6  * This software is available to you under a choice of one of two
7  * licenses.  You may choose to be licensed under the terms of the GNU
8  * General Public License (GPL) Version 2, available from the file
9  * COPYING in the main directory of this source tree, or the
10  * OpenIB.org BSD license below:
11  *
12  *     Redistribution and use in source and binary forms, with or
13  *     without modification, are permitted provided that the following
14  *     conditions are met:
15  *
16  *      - Redistributions of source code must retain the above
17  *        copyright notice, this list of conditions and the following
18  *        disclaimer.
19  *
20  *      - Redistributions in binary form must reproduce the above
21  *        copyright notice, this list of conditions and the following
22  *        disclaimer in the documentation and/or other materials
23  *        provided with the distribution.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32  * SOFTWARE.
33  *
34  * $Id$
35  */
36
37 #include "getopt.h"
38 #include "get_clock.h"
39 #include "perf_defs.h"
40
41
42 #define SIGNAL 1
43 #define MAX_INLINE 400
44
45
46 static int page_size;
47 cycles_t                *tstamp;
48
49 struct user_parameters {
50         const char              *servername;
51         int connection_type;
52         int mtu;
53         int signal_comp;
54         int all; /* run all msg size */
55         int iters;
56         int tx_depth;
57         int use_event;
58 };
59
60 struct report_options {
61         int unsorted;
62         int histogram;
63         int cycles;   /* report delta's in cycles, not microsec's */
64 };
65
66
67
68 void
69 pp_cq_comp_cb(
70         IN              const   ib_cq_handle_t                          h_cq,
71         IN                              void                                            *cq_context )
72 {
73         UNUSED_PARAM( h_cq );
74         UNUSED_PARAM( cq_context);
75         return ;
76 }
77
78
79 static struct pingpong_context *pp_init_ctx(unsigned int size,int port,struct user_parameters *user_parm) {
80
81         struct pingpong_context *ctx;
82         ib_api_status_t                         ib_status = IB_SUCCESS; 
83         size_t                                  guid_count;
84         ib_net64_t                              *ca_guid_array;
85
86
87         
88         ctx = malloc(sizeof *ctx);
89         if (!ctx)
90                 return NULL;
91
92         ctx->qp = malloc(sizeof (ib_qp_handle_t));
93         if (!ctx->qp) {
94                 perror("malloc");
95                 return NULL;
96         }
97
98         ctx->qp_attr = malloc(sizeof (ib_qp_attr_t));
99         if (!ctx->qp_attr) {
100                 perror("malloc");
101                 return NULL;
102         }
103
104         ctx->size = size;
105         ctx->tx_depth = user_parm->tx_depth;
106         /* in case of UD need space for the GRH */
107         if (user_parm->connection_type==UD) {
108                 ctx->buf = malloc(( size + 40 ) * 2); //PORTED ALINGED
109                 if (!ctx->buf) {
110                         fprintf(stderr, "Couldn't allocate work buf.\n");
111                         return NULL;
112                 }
113                 memset(ctx->buf, 0, ( size + 40 ) * 2);
114         } else {
115                 ctx->buf = malloc( size * 2); //PORTED ALINGED
116                 if (!ctx->buf) {
117                         fprintf(stderr, "Couldn't allocate work buf.\n");
118                         return NULL;
119                 }
120                 memset(ctx->buf, 0, size * 2);
121         }
122
123
124         ctx->post_buf = (char*)ctx->buf + (size - 1);
125         ctx->poll_buf = (char*)ctx->buf + (2 * size - 1);
126
127                 /*
128          * Open the AL instance
129          */
130         ib_status = ib_open_al(&ctx->al);
131         if(ib_status != IB_SUCCESS)
132         {
133                 fprintf(stderr,"ib_open_al failed status = %d\n", ib_status);
134                 return NULL;
135         }
136
137         /*
138          * Get the Local CA Guids
139          */
140         ib_status = ib_get_ca_guids(ctx->al, NULL, &guid_count);
141         if(ib_status != IB_INSUFFICIENT_MEMORY)
142         {
143                 fprintf(stderr,"ib_get_ca_guids1 failed status = %d\n", (uint32_t)ib_status);
144                 return NULL;
145         }
146         
147         /*
148          * If no CA's Present then return
149          */
150
151         if(guid_count == 0)
152                 return NULL;
153
154         
155         ca_guid_array = (ib_net64_t*)malloc(sizeof(ib_net64_t) * guid_count);
156         
157         ib_status = ib_get_ca_guids(ctx->al, ca_guid_array, &guid_count);
158         if(ib_status != IB_SUCCESS)
159         {
160                 fprintf(stderr,"ib_get_ca_guids2 failed with status = %d\n", ib_status);
161                 return NULL;
162         }
163
164         /*
165          * Open only the first HCA
166          */
167         /* Open the CA */
168         ib_status = ib_open_ca(ctx->al ,ca_guid_array[0] ,NULL,
169                 NULL,   //ca_context
170                 &ctx->ca);
171
172         if(ib_status != IB_SUCCESS)
173         {
174                 fprintf(stderr,"ib_open_ca failed with status = %d\n", ib_status);
175                 return NULL;
176         }
177
178         //xxx
179         //printf("ib_open_ca passed i=%d\n",i); 
180         //xxx
181
182
183         {
184
185
186                 /* Query the CA */
187                 uint32_t bsize = 0;
188                 ib_status = ib_query_ca(ctx->ca, NULL, &bsize);
189                 if(ib_status != IB_INSUFFICIENT_MEMORY)
190                 {
191                         fprintf(stderr, "Failed to query device props");
192                         return NULL;
193                 }
194
195                 ctx->ca_attr = (ib_ca_attr_t *)malloc(bsize);
196
197                 ib_status = ib_query_ca(ctx->ca, ctx->ca_attr, &bsize);
198                 if(ib_status != IB_SUCCESS)
199                 {
200                         printf("ib_query_ca failed with status = %d\n", ib_status);
201                         return NULL;
202                 }
203                 if (user_parm->mtu == 0) {/*user did not ask for specific mtu */
204                         if (ctx->ca_attr->dev_id == 23108) {
205                                 user_parm->mtu = 1024;
206                         } else {
207                                 user_parm->mtu = 2048;
208                         }
209                 }
210         }
211         if (user_parm->use_event) {
212 //PORTED                ctx->channel = ibv_create_comp_channel(ctx->context);
213                 ctx->channel = NULL;//remove when PORTED
214                 if (!ctx->channel) {
215                         fprintf(stderr, "Couldn't create completion channel\n");
216                         return NULL;
217                 }
218         } else
219                 ctx->channel = NULL;                  
220
221         ib_status = ib_alloc_pd(ctx->ca ,
222                                                 IB_PDT_NORMAL,
223                                                 ctx, //pd_context
224                                                 &ctx->pd);
225         if (ib_status != IB_SUCCESS) {
226                 fprintf(stderr, "Couldn't allocate PD\n");
227                 return NULL;
228         }
229
230
231         {
232                 ib_mr_create_t                  mr_create;
233                 ib_cq_create_t                  cq_create;
234                 /* We dont really want IBV_ACCESS_LOCAL_WRITE, but IB spec says:
235                  * The Consumer is not allowed to assign Remote Write or Remote Atomic to
236                  * a Memory Region that has not been assigned Local Write. */
237                 if (user_parm->connection_type==UD) {
238                         mr_create.length = (size + 40 ) * 2;
239                 } else {
240                         mr_create.length = size * 2;
241                 }
242                         
243                 mr_create.vaddr = ctx->buf;
244                 mr_create.access_ctrl = IB_AC_RDMA_WRITE| IB_AC_LOCAL_WRITE;
245                 
246                 ib_status = ib_reg_mem(ctx->pd ,&mr_create ,&ctx->lkey ,&ctx->rkey ,&ctx->mr);
247                 if (ib_status != IB_SUCCESS) {
248                         fprintf(stderr, "Couldn't allocate MR\n");
249                         return NULL;
250                 }
251
252
253                 cq_create.size = user_parm->tx_depth*2;
254                 cq_create.h_wait_obj = NULL;
255                 cq_create.pfn_comp_cb = pp_cq_comp_cb;
256                 ib_status = ib_create_cq(ctx->ca,&cq_create ,ctx, NULL, &ctx->rcq);
257                 if (ib_status != IB_SUCCESS) {
258                         fprintf(stderr, "Couldn't create CQ\n");
259                         return NULL;
260                 }
261
262
263                 cq_create.size = user_parm->tx_depth*2;
264                 cq_create.h_wait_obj = NULL;
265                 cq_create.pfn_comp_cb = pp_cq_comp_cb;
266                 ib_status = ib_create_cq(ctx->ca,&cq_create ,ctx, NULL, &ctx->scq);
267                 if (ib_status != IB_SUCCESS) {
268                         fprintf(stderr, "Couldn't create CQ\n");
269                         return NULL;
270                 }
271         }
272
273         {
274                 ib_qp_create_t  qp_create;
275                 memset(&qp_create, 0, sizeof(ib_qp_create_t));
276                 qp_create.h_sq_cq       = ctx->scq;
277                 qp_create.h_rq_cq       = ctx->rcq;
278                 qp_create.sq_depth      = user_parm->tx_depth;
279                 qp_create.rq_depth      = user_parm->tx_depth;
280                 qp_create.sq_sge        = 1;
281                 qp_create.rq_sge        = 1;
282                 //TODO MAX_INLINE
283                 
284                 switch (user_parm->connection_type) {
285                 case RC :
286                         qp_create.qp_type= IB_QPT_RELIABLE_CONN;
287                         break;
288                 case UC :
289                         qp_create.qp_type = IB_QPT_UNRELIABLE_CONN;
290                         break;
291                 case UD :
292                         qp_create.qp_type = IB_QPT_UNRELIABLE_DGRM;
293                         break;
294                 default:
295                         fprintf(stderr, "Unknown connection type %d \n",user_parm->connection_type);
296                         return NULL;
297                 }
298
299                 qp_create.sq_signaled = FALSE;
300                 /*attr.sq_sig_all = 0;*/
301
302                 ib_status = ib_create_qp(ctx->pd, &qp_create,NULL,NULL,&ctx->qp[0]);
303                 if (ib_status != IB_SUCCESS){
304                         fprintf(stderr, "Couldn't create QP\n");
305                         return NULL;
306                 }
307         }
308
309         {
310                 ib_qp_mod_t     qp_modify;
311                 ib_qp_attr_t    qp_attr;
312                 memset(&qp_modify, 0, sizeof(ib_qp_mod_t));
313                 qp_modify.req_state = IB_QPS_INIT;
314                 qp_modify.state.init.pkey_index = 0 ;
315                 qp_modify.state.init.primary_port = (uint8_t)port;
316                 if (user_parm->connection_type==UD) {
317                         qp_modify.state.init.qkey = 0x11111111;
318                 } else {
319                         qp_modify.state.init.access_ctrl = IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE;
320                 }
321                 
322                 ib_status = ib_modify_qp(ctx->qp[0], &qp_modify);
323                 if (ib_status != IB_SUCCESS){
324                         fprintf(stderr, "Failed to modify QP to INIT\n");
325                         return NULL;
326                 }
327
328
329                 memset(&qp_attr, 0, sizeof(ib_qp_attr_t));
330                 ib_status = ib_query_qp(ctx->qp[0], &ctx->qp_attr[0]);
331                 if (ib_status != IB_SUCCESS){
332                         fprintf(stderr, "Failed to modify QP to INIT\n");
333                         return NULL;
334                 }
335         }
336
337         
338         //send
339         ctx->wr.wr_id = PINGPONG_SEND_WRID;
340         ctx->wr.ds_array = &ctx->list;
341         ctx->wr.num_ds = 1;
342         ctx->wr.wr_type = WR_SEND;
343         ctx->wr.p_next       = NULL;    
344
345         //recieve
346         ctx->rwr.wr_id      = PINGPONG_RECV_WRID;
347         ctx->rwr.ds_array = &ctx->recv_list;
348         ctx->rwr.num_ds = 1;
349         ctx->rwr.p_next = NULL;
350         return ctx;
351 }
352
353 static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn,
354                           struct pingpong_dest *dest,struct user_parameters *user_parm,int index)
355 {
356         ib_api_status_t ib_status;
357         ib_qp_mod_t     attr;
358         memset(&attr, 0, sizeof(ib_qp_mod_t));
359
360         attr.req_state          = IB_QPS_RTR;
361         switch (user_parm->mtu) {
362         case 256 : 
363                 attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_256;
364                 break;
365         case 512 :
366                 attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_512;
367                 break;
368         case 1024 :
369                 attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_1024;
370                 break;
371         case 2048 :
372                 attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_2048;
373                 break;
374         }
375         printf("Mtu : %d\n", user_parm->mtu);
376         attr.state.rtr.dest_qp  = (dest->qpn);
377         attr.state.rtr.rq_psn   = (dest->psn);
378         if (user_parm->connection_type==RC) {
379                 attr.state.rtr.resp_res = 1;
380                 attr.state.rtr.rnr_nak_timeout = 12;
381         }
382         attr.state.rtr.primary_av.grh_valid = 0;
383         attr.state.rtr.primary_av.dlid = dest->lid;
384         attr.state.rtr.primary_av.sl = 0;
385         attr.state.rtr.primary_av.path_bits = 0;
386         attr.state.rtr.primary_av.port_num = (uint8_t)port;
387         attr.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS;
388         attr.state.rtr.opts = IB_MOD_QP_LOCAL_ACK_TIMEOUT |
389                                         IB_MOD_QP_RESP_RES |
390                                         IB_MOD_QP_PRIMARY_AV;
391
392
393         ib_status = ib_modify_qp(ctx->qp[0], &attr);
394         if(ib_status != IB_SUCCESS){
395                         fprintf(stderr, "Failed to modify UC QP to RTR\n");
396                         return 1;
397         }
398
399
400         if (user_parm->connection_type == UD) {
401                 ib_av_attr_t    av_attr;
402
403                 av_attr.grh_valid = 0;
404                 av_attr.dlid = dest->lid;
405                 av_attr.dlid = dest->lid;
406                 av_attr.sl = 0;
407                 av_attr.path_bits = 0;
408                 av_attr.port_num = (uint8_t)port;
409                 av_attr.static_rate = IB_PATH_RECORD_RATE_10_GBS;
410                 ib_status = ib_create_av(ctx->pd,&av_attr, &ctx->av);
411                 if (ib_status != IB_SUCCESS) {
412                         fprintf(stderr, "Failed to create AH for UD\n");
413                         return 1;
414                 }
415         }
416         memset(&attr, 0, sizeof(ib_qp_mod_t));
417         attr.req_state  = IB_QPS_RTS;
418         attr.state.rts.sq_psn = my_psn;
419
420         if (user_parm->connection_type == RC) {
421                 attr.state.rts.resp_res = 1;
422                 attr.state.rts.local_ack_timeout = 14;
423                 attr.state.rts.retry_cnt = 7;
424                 attr.state.rts.rnr_retry_cnt = 7;
425                 attr.state.rts.opts = IB_MOD_QP_RNR_RETRY_CNT |
426                                                 IB_MOD_QP_RETRY_CNT |
427                                                 IB_MOD_QP_LOCAL_ACK_TIMEOUT;
428                                                 
429         }       
430         ib_status = ib_modify_qp(ctx->qp[index], &attr);
431         if(ib_status != IB_SUCCESS){
432                 fprintf(stderr, "Failed to modify UC QP to RTS\n");
433                 return 1;
434         }
435
436         
437         
438                 /* post recieve max msg size*/
439         {
440                 int i;
441                 ib_recv_wr_t      *bad_wr_recv;
442                 //recieve
443                 ctx->rwr.wr_id      = PINGPONG_RECV_WRID;
444                 ctx->rwr.ds_array = &ctx->recv_list;
445                 ctx->rwr.num_ds = 1;
446                 ctx->rwr.p_next = NULL;
447                 ctx->recv_list.vaddr = (uintptr_t) ctx->buf;
448                 if (user_parm->connection_type==UD) {
449                         ctx->recv_list.length = ctx->size + 40;
450                 } else {
451                         ctx->recv_list.length = ctx->size;
452                 }
453                 ctx->recv_list.lkey = ctx->lkey;
454                 for (i = 0; i < user_parm->tx_depth / 2; ++i) {
455                         if (ib_post_recv(ctx->qp[index], &ctx->rwr, &bad_wr_recv)) {
456                                 fprintf(stderr, "Couldn't post recv: counter=%d\n", i);
457                                 return 14;
458                         }
459                 }
460         }
461         return 0;
462 }
463
464 static SOCKET pp_open_port(struct pingpong_context *ctx, const char * servername,
465                         int ib_port, int port, struct pingpong_dest **p_my_dest,
466                         struct pingpong_dest **p_rem_dest,struct user_parameters *user_parm)
467 {
468         struct pingpong_dest    *my_dest;
469         struct pingpong_dest    *rem_dest;
470         SOCKET                          sockfd;
471         int                                     rc;
472         int                                     i;
473         int                                     numofqps = 1;
474         
475         /* Create connection between client and server.
476          * We do it by exchanging data over a TCP socket connection. */
477
478         
479         my_dest = malloc( sizeof (struct pingpong_dest) * numofqps);
480         if (!my_dest){
481                 perror("malloc");
482                 return INVALID_SOCKET;
483         }
484
485         rem_dest = malloc(sizeof (struct pingpong_dest) * numofqps );
486         if (!rem_dest){
487                 perror("malloc");
488                 return INVALID_SOCKET;
489         }
490
491         sockfd = servername ? pp_client_connect(servername, port) :
492                 pp_server_connect(port);
493
494         if (sockfd  == INVALID_SOCKET) {
495                 printf("pp_connect_sock(%s,%d) failed (%d)!\n",
496                        servername, port, sockfd);
497                 return INVALID_SOCKET;
498         }
499
500         
501         for (i =0 ;i<numofqps;i ++) 
502         {
503                 /* Create connection between client and server.
504                 * We do it by exchanging data over a TCP socket connection. */
505                 
506                 my_dest[i].lid = ctx->ca_attr->p_port_attr[ib_port-1].lid;
507                 my_dest[i].psn = rand() & 0xffffff;
508                 if (!my_dest[i].lid) {
509                         fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n");
510                         return 1;
511                 }
512                 my_dest[i].qpn = ctx->qp_attr[i].num;
513                 /* TBD this should be changed inot VA and different key to each qp */
514                 my_dest[i].rkey = ctx->rkey;
515                 my_dest[i].vaddr = (uintptr_t)ctx->buf + ctx->size;
516
517                 printf("  local address:  LID %#04x, QPN %#06x, PSN %#06x, "
518                 "RKey %#08x VAddr %#016Lx\n",
519                 my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn,
520                 my_dest[i].rkey, my_dest[i].vaddr);
521
522                 rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]):
523                                                 pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]);
524                 if (rc)
525                         return INVALID_SOCKET;
526                 printf("  remote address: LID %#04x, QPN %#06x, PSN %#06x, "
527                 "RKey %#08x VAddr %#016Lx\n",
528                 rem_dest[i].lid, rem_dest[i].qpn, rem_dest[i].psn,
529                 rem_dest[i].rkey, rem_dest[i].vaddr);
530
531                 if (pp_connect_ctx(ctx, ib_port, my_dest[i].psn, &rem_dest[i], user_parm, i))
532                         return INVALID_SOCKET;
533                 /* An additional handshake is required *after* moving qp to RTR.
534                 Arbitrarily reuse exch_dest for this purpose. */
535                 rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]):
536                                                 pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]);
537                 if (rc)
538                         return INVALID_SOCKET;
539         }
540         *p_rem_dest = rem_dest;
541         *p_my_dest = my_dest;
542         return sockfd;
543 }
544
545
546
547 static void usage(const char *argv0)
548 {
549         printf("Usage:\n");
550         printf("  %s            start a server and wait for connection\n", argv0);
551         printf("  %s <host>     connect to server at <host>\n", argv0);
552         printf("\n");
553         printf("Options:\n");
554         printf("  -p, --port=<port>            listen on/connect to port <port> (default 18515)\n");
555         printf("  -c, --connection=<RC/UC>     connection type RC/UC (default RC)\n");
556         printf("  -m, --mtu=<mtu>              mtu size (default 2048)\n");
557         printf("  -d, --ib-dev=<dev>           use IB device <dev> (default first device found)\n");
558         printf("  -i, --ib-port=<port>         use port <port> of IB device (default 1)\n");
559         printf("  -s, --size=<size>            size of message to exchange (default 1)\n");
560         printf("  -t, --tx-depth=<dep>         size of tx queue (default 50)\n");
561         printf("  -l, --signal                 signal completion on each msg\n");
562         printf("  -a, --all                    Run sizes from 2 till 2^23\n");
563         printf("  -n, --iters=<iters>          number of exchanges (at least 2, default 1000)\n");
564         printf("  -C, --report-cycles          report times in cpu cycle units (default microseconds)\n");
565         printf("  -H, --report-histogram       print out all results (default print summary only)\n");
566         printf("  -U, --report-unsorted        (implies -H) print out unsorted results (default sorted)\n");
567         printf("  -V, --version                display version number\n");
568     printf("  -e, --events                 sleep on CQ events (default poll)\n");
569 }
570
571 /*
572  * When there is an
573  *      odd number of samples, the median is the middle number.
574  *      even number of samples, the median is the mean of the
575  *              two middle numbers.
576  *
577  */
578 static inline cycles_t get_median(int n, cycles_t delta[])
579 {
580         if (n % 2)
581                 return(delta[n / 2] + delta[n / 2 - 1]) / 2;
582         else
583                 return delta[n / 2];
584 }
585
586
587 static void print_report(struct report_options * options,
588                          unsigned int iters, cycles_t *tstamp,int size)
589 {
590         double cycles_to_units;
591         cycles_t median;
592         unsigned int i;
593         const char* units;
594         cycles_t *delta = malloc(iters * sizeof *delta);
595
596         if (!delta) {
597                 perror("malloc");
598                 return;
599         }
600
601         for (i = 0; i < iters - 1; ++i)
602                 delta[i] = tstamp[i + 1] - tstamp[i];
603
604
605         if (options->cycles) {
606                 cycles_to_units = 1;
607                 units = "cycles";
608         } else {
609                 cycles_to_units = get_cpu_mhz()/1000000;
610                 units = "usec";
611         }
612
613         if (options->unsorted) {
614                 printf("#, %s\n", units);
615                 for (i = 0; i < iters - 1; ++i)
616                         printf("%d, %g\n", i + 1, delta[i] / cycles_to_units / 2);
617         }
618
619         qsort(delta, iters - 1, sizeof *delta, cycles_compare);
620
621         if (options->histogram) {
622                 printf("#, %s\n", units);
623                 for (i = 0; i < iters - 1; ++i)
624                         printf("%d, %g\n", i + 1, delta[i] / cycles_to_units / 2);
625         }
626
627         median = get_median(iters - 1, delta);
628         printf("%7d        %d        %7.2f        %7.2f          %7.2f\n",
629                size,iters,delta[0] / cycles_to_units / 2,
630                delta[iters - 2] / cycles_to_units / 2,median / cycles_to_units / 2);
631         free(delta);
632 }
633
634 int run_iter(struct pingpong_context *ctx, struct user_parameters *user_param,
635              struct pingpong_dest *rem_dest, int size)
636 {
637         ib_api_status_t ib_status;
638         ib_qp_handle_t  qp;
639         ib_recv_wr_t            rwr;
640         ib_recv_wr_t            *bad_wr_recv;
641         volatile char           *poll_buf; 
642         volatile char           *post_buf;
643
644         int                             scnt, rcnt, ccnt, poll;
645         int                             iters;
646         int                             tx_depth;
647         iters = user_param->iters;
648         tx_depth = user_param->tx_depth;
649
650         ///send //
651         if (user_param->connection_type==UD) {
652                 ctx->list.vaddr = (uintptr_t) ctx->buf + 40;
653         } else {
654                 ctx->list.vaddr = (uintptr_t) ctx->buf;
655         }
656         ctx->list.length = size;
657         ctx->list.lkey = ctx->lkey;
658         if (user_param->connection_type==UD) {
659                 ctx->wr.dgrm.ud.h_av = ctx->av;
660                 ctx->wr.dgrm.ud.remote_qp = rem_dest->qpn;
661                 ctx->wr.dgrm.ud.remote_qkey = 0x11111111;
662         }
663         
664         /// receive //
665         rwr = ctx->rwr;
666         ctx->recv_list.vaddr = (uintptr_t) ctx->buf;
667         if (user_param->connection_type==UD) {
668                 ctx->recv_list.length = ctx->size + 40;
669         } else {
670                 ctx->recv_list.length = ctx->size;
671         }
672
673         ctx->recv_list.lkey = ctx->lkey;
674
675         scnt = 0;
676         rcnt = 0;
677         ccnt = 0;
678         poll = 0;
679         poll_buf = ctx->poll_buf;
680         post_buf = ctx->post_buf;
681         qp = ctx->qp[0];
682         if ((uint32_t)size > ctx->qp_attr[0].sq_max_inline || size == 0) {/* complaince to perf_main  don't signal*/
683                 ctx->wr.send_opt = 0;
684         } else {
685                 ctx->wr.send_opt = IB_SEND_OPT_INLINE;
686         }
687
688         while (scnt < iters || rcnt < iters) {
689                 if (rcnt < iters && !(scnt < 1 && user_param->servername)) {
690                         ib_wc_t wc;
691                         ib_wc_t *p_wc_done,*p_wc_free;
692
693                         p_wc_free = &wc;
694                         p_wc_done = NULL;
695                         p_wc_free->p_next = NULL;
696                         PERF_DEBUG("rcnt %d\n",rcnt);
697                         PERF_DEBUG("scnt %d\n",scnt);
698                         /*Server is polling on recieve first */
699                         ++rcnt;
700                         if (ib_post_recv(qp, &rwr, &bad_wr_recv)) {
701                                 fprintf(stderr, "Couldn't post recv: rcnt=%d\n",
702                                         rcnt);
703                                 return 15;
704                         }
705
706 #if PORTED
707                         if (user_param->use_event) {
708                                 struct ibv_cq *ev_cq;
709                                 void                    *ev_ctx;
710
711                                 if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) {
712                                         fprintf(stderr, "Failed to get receive cq_event\n");
713                                         return 1;
714                                 }
715
716                                 if (ev_cq != ctx->rcq) {
717                                         fprintf(stderr, "CQ event for unknown RCQ %p\n", ev_cq);
718                                         return 1;
719                                 }
720
721                                 if (ibv_req_notify_cq(ctx->rcq, 0)) {
722                                         fprintf(stderr, "Couldn't request RCQ notification\n");
723                                         return 1;
724                                 }
725                         }
726 #endif
727
728                         do {
729                                 ib_status = ib_poll_cq(ctx->rcq,&p_wc_free, &p_wc_done);
730                         } while (!user_param->use_event && ib_status == IB_NOT_FOUND);
731
732                         if (ib_status != IB_SUCCESS) {
733                                 fprintf(stderr, "Poll Recieve CQ failed %d\n", ib_status);
734                                 return 12;
735                         }
736                         
737                         if (p_wc_done->status != IB_WCS_SUCCESS) {
738                                 fprintf(stderr, "Recieve Completion wth error at %s:\n",
739                                         user_param->servername ? "client" : "server");
740                                 fprintf(stderr, "Failed status %d: wr_id %d\n",
741                                         wc.status, (int) wc.wr_id);
742                                 fprintf(stderr, "scnt=%d, rcnt=%d, ccnt=%d\n",
743                                         scnt, rcnt, ccnt);
744                                 return 13;
745                         }
746                 }
747                 
748                 if (scnt < iters ) {
749                         ib_send_wr_t            *bad_wr;
750
751                         PERF_DEBUG("rcnt1 %d\n",rcnt);
752                         PERF_DEBUG("scnt1 %d\n",scnt);
753                         if (ccnt == (tx_depth - 2) || (user_param->signal_comp == SIGNAL)
754                             || (scnt == (iters - 1)) ) {
755                                 ccnt = 0;
756                                 poll=1;
757                                 if ((uint32_t)size > ctx->qp_attr[0].sq_max_inline || size == 0) {/* complaince to perf_main */
758                                         ctx->wr.send_opt = IB_SEND_OPT_SIGNALED;
759                                 } else {
760                                         ctx->wr.send_opt = IB_SEND_OPT_SIGNALED | IB_SEND_OPT_INLINE;
761                                 }
762
763                         }
764                         
765                         /* client post first */
766                         tstamp[scnt] = get_cycles();
767                         *post_buf = (char)++scnt;
768                         if (ib_post_send(qp,&ctx->wr, &bad_wr)) {
769                                 fprintf(stderr, "Couldn't post send: scnt=%d\n",
770                                         scnt);
771                                 return 11;
772                         }
773                 }
774                 if (poll == 1) {
775                         ib_wc_t wc;
776                         ib_wc_t *p_wc_done,*p_wc_free;
777
778                         PERF_DEBUG("rcnt2 %d\n",rcnt);
779                         PERF_DEBUG("scnt2 %d\n",scnt);
780                         p_wc_free = &wc;
781                         p_wc_done = NULL;
782                         p_wc_free->p_next = NULL;
783
784 #if PORTED
785                         if (user_param->use_event) {
786                                 struct ibv_cq *ev_cq;
787                                 void          *ev_ctx;
788
789                                 if (ibv_get_cq_event(ctx->channel, &ev_cq, &ev_ctx)) {
790                                         fprintf(stderr, "Failed to get send cq_event\n");
791                                         return 1;
792                                 }
793
794                                 if (ev_cq != ctx->scq) {
795                                         fprintf(stderr, "CQ event for unknown SCQ %p\n", ev_cq);
796                                         return 1;
797                                 }
798
799                                 if (ibv_req_notify_cq(ctx->scq, 0)) {
800                                         fprintf(stderr, "Couldn't request SCQ notification\n");
801                                         return 1;
802                                 }
803                         }
804
805 #endif
806
807                         /* poll on scq */
808                         do {
809                                 ib_status = ib_poll_cq(ctx->scq, &p_wc_free, &p_wc_done);
810                         } while (!user_param->use_event && ib_status == IB_NOT_FOUND);
811
812                         if (ib_status != IB_SUCCESS) {
813                                 fprintf(stderr, "Poll Recieve CQ failed %d\n", ib_status);
814                                 return 12;
815                         }
816                         
817                         if (wc.status != IB_WCS_SUCCESS) {
818                                 fprintf(stderr, "Recieve Completion wth error at %s:\n",
819                                         user_param->servername ? "client" : "server");
820                                 fprintf(stderr, "Failed status %d: wr_id %d\n",
821                                         wc.status, (int) wc.wr_id);
822                                 fprintf(stderr, "scnt=%d, rcnt=%d, ccnt=%d\n",
823                                         scnt, rcnt, ccnt);
824                                 return 13;
825                         }
826                         
827                         poll = 0;
828                         if ((uint32_t)size > ctx->qp_attr[0].sq_max_inline || size == 0) {/* complaince to perf_main don't signal*/
829                                 ctx->wr.send_opt = 0;
830                         } else {
831                                 ctx->wr.send_opt = IB_SEND_OPT_INLINE;
832                         }
833
834                 }
835                 ++ccnt;
836         }
837
838         return(0);
839 }
840
841
842
843 int __cdecl main(int argc, char *argv[])
844 {
845
846         struct pingpong_context *ctx;
847         struct pingpong_dest     *my_dest;
848         struct pingpong_dest     *rem_dest;
849         struct user_parameters  user_param;
850         char                            *ib_devname = NULL;
851         int                             port = 18515;
852         int                             ib_port = 1;
853         unsigned                        size = 2;
854         SOCKET                  sockfd = INVALID_SOCKET;
855         int                             i = 0;
856         int                             size_max_pow = 24;
857         WSADATA         wsaData;
858         int                             iResult; 
859
860
861         struct report_options    report = {0};
862
863         /* init default values to user's parameters */
864         memset(&user_param, 0, sizeof(struct user_parameters));
865         user_param.mtu = 0;
866         user_param.iters = 1000;
867         user_param.tx_depth = 50;
868         user_param.servername = NULL;
869         user_param.use_event = 0;
870         /* Parameter parsing. */
871         while (1) {
872                 int c;
873
874                 static struct option long_options[] = {
875                         { "port",                       1,NULL, 'p' },
876                         { "connection", 1,NULL, 'c' },
877                         { "mtu",                        1,NULL, 'm' },
878                         { "ib-dev",             1,NULL, 'd' },
879                         { "ib-port",            1,NULL, 'i' },
880                         { "size",                       1,NULL, 's' },
881                         { "iters",                      1,NULL, 'n' },
882                         { "tx-depth",           1,NULL, 't' },
883                         { "signal",             0,NULL, 'l' },
884                         { "all",                        0,NULL, 'a' },
885                         { "report-cycles",      0,NULL, 'C' },
886                         { "report-histogram",   0,NULL, 'H' },
887                         { "report-unsorted",    0,NULL, 'U' },
888                         { "version",                    0,NULL, 'V' },
889                         { "events",                     0,NULL, 'e' },
890                         { 0 }
891                 };
892
893                 c = getopt_long(argc, argv, "p:c:m:d:i:s:n:t:laeCHUV", long_options, NULL);
894                 if (c == -1)
895                         break;
896
897                 switch (c) {
898                 case 'p':
899                         port = strtol(optarg, NULL, 0);
900                         if (port < 0 || port > 65535) {
901                                 usage(argv[0]);
902                                 return 1;
903                         }
904                         break;
905                 case 'c':
906                         if (strcmp("UC",optarg)==0)
907                                 user_param.connection_type=UC;
908                         if (strcmp("UD",optarg)==0)
909                                 user_param.connection_type=UD;
910                         /* default is 0 for any other option RC*/
911                         break;
912                 case 'e':
913                         ++user_param.use_event;
914                         break;
915                 case 'm':
916                         user_param.mtu = strtol(optarg, NULL, 0);
917                         break;
918                 case 'l':
919                         user_param.signal_comp = SIGNAL;
920                         break;
921                 case 'a':
922                         user_param.all = SIGNAL;
923                         break;
924                 case 'V':
925                         printf("perftest version : %.2f\n",VERSION);
926                         return 0;
927                         break;
928                 case 'd':
929                         ib_devname = _strdup(optarg);
930                         break;
931
932                 case 'i':
933                         ib_port = strtol(optarg, NULL, 0);
934                         if (ib_port < 0) {
935                                 usage(argv[0]);
936                                 return 2;
937                         }
938                         break;
939
940                 case 's':
941                         size = strtol(optarg, NULL, 0);
942                         if (size < 1) {
943                                 usage(argv[0]); return 3;
944                         }
945                         break;
946
947                 case 't':
948                         user_param.tx_depth = strtol(optarg, NULL, 0);
949                         if (user_param.tx_depth < 1) {
950                                 usage(argv[0]); return 4;
951                         }
952                         break;
953
954                 case 'n':
955                         user_param.iters = strtol(optarg, NULL, 0);
956                         if (user_param.iters < 2) {
957                                 usage(argv[0]);
958                                 return 5;
959                         }
960
961                         break;
962
963                 case 'C':
964                         report.cycles = 1;
965                         break;
966
967                 case 'H':
968                         report.histogram = 1;
969                         break;
970
971                 case 'U':
972                         report.unsorted = 1;
973                         break;
974
975                 default:
976                         usage(argv[0]);
977                         return 5;
978                 }
979         }
980
981         if (optind == argc - 1)
982                 user_param.servername = _strdup(argv[optind]);
983         else if (optind < argc) {
984                 usage(argv[0]);
985                 return 6;
986         }
987
988         /*
989          *  Done with parameter parsing. Perform setup.
990          */
991         tstamp = malloc(user_param.iters * sizeof *tstamp);
992         if (!tstamp) {
993                 perror("malloc");
994                 return 10;
995         }
996         /* Print header data */
997         printf("------------------------------------------------------------------\n");
998         printf("                    Send Latency Test\n");
999         printf("Inline data is used up to 400 bytes message\n");
1000         if (user_param.connection_type==RC) {
1001                 printf("Connection type : RC\n");
1002         } else if (user_param.connection_type==UC) { 
1003                 printf("Connection type : UC\n");
1004         } else {
1005                 printf("Connection type : UD\n");
1006         }
1007
1008         /* Done with parameter parsing. Perform setup. */
1009
1010         // Initialize Winsock
1011         iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
1012         if (iResult != NO_ERROR) {
1013                 printf("Error at WSAStartup()\n");
1014                 return 1;
1015         }
1016
1017         
1018         if (user_param.all == ALL && user_param.connection_type!=UD) {
1019                 /*since we run all sizes */
1020                 printf("test\n");
1021                 size = 8388608; /*2^23 */
1022         } else if (user_param.connection_type==UD ) {
1023                 printf("Max msg size in UD is 2048 changing to 2048\n");
1024                 size = 2048;
1025         }
1026         
1027         srand(GetCurrentProcessId() * GetTickCount());
1028
1029         //TODO: get pagesize from sysinfo
1030         page_size = 4096;
1031
1032         //TODO  get the device names
1033         
1034         ctx = pp_init_ctx( size, ib_port,&user_param);
1035         if (!ctx)
1036                 return 8;
1037
1038         sockfd = pp_open_port(ctx, user_param.servername, ib_port, port,&my_dest,&rem_dest,&user_param);
1039         if (sockfd == INVALID_SOCKET)
1040                 return 9;
1041
1042
1043 #if PORTED
1044         if (user_param.use_event) {
1045                 printf("Test with events.\n");
1046                 if (ibv_req_notify_cq(ctx->rcq, 0)) {
1047                         fprintf(stderr, "Couldn't request RCQ notification\n");
1048                         return 1;
1049                 } 
1050                 if (ibv_req_notify_cq(ctx->scq, 0)) {
1051                         fprintf(stderr, "Couldn't request SCQ notification\n");
1052                         return 1;
1053                 }
1054         }
1055 #endif
1056  
1057         printf("------------------------------------------------------------------\n");
1058         printf(" #bytes #iterations    t_min[usec]    t_max[usec]  t_typical[usec]\n");
1059
1060         if (user_param.all == 1) {
1061                 if (user_param.connection_type==UD) {
1062                         size_max_pow = 12;
1063                 }
1064                 for (i = 1; i < size_max_pow ; ++i) {
1065                         size = 1 << i;
1066                         if(run_iter(ctx, &user_param, rem_dest, size))
1067                                 return 17;
1068
1069                         print_report(&report, user_param.iters, tstamp, size);
1070                 }
1071         } else {
1072                 if(run_iter(ctx, &user_param, rem_dest, size))
1073                         return 18;      
1074                 print_report(&report, user_param.iters, tstamp, size);
1075         }
1076         printf("------------------------------------------------------------------\n");
1077
1078         send(sockfd, "done", sizeof "done",0);
1079         closesocket(sockfd);
1080
1081
1082         free(tstamp);
1083         return 0;
1084 }