[TOOLS] fix send_bw test for UD.
[mirror/winof/.git] / tools / perftests / user / write_bw / write_bw.c
1 /*
2  * Copyright (c) 2005 Topspin Communications.  All rights reserved.
3  * Copyright (c) 2005 Mellanox Technologies Ltd.  All rights reserved.
4  *
5  * This software is available to you under a choice of one of two
6  * licenses.  You may choose to be licensed under the terms of the GNU
7  * General Public License (GPL) Version 2, available from the file
8  * COPYING in the main directory of this source tree, or the
9  * OpenIB.org BSD license below:
10  *
11  *     Redistribution and use in source and binary forms, with or
12  *     without modification, are permitted provided that the following
13  *     conditions are met:
14  *
15  *      - Redistributions of source code must retain the above
16  *        copyright notice, this list of conditions and the following
17  *        disclaimer.
18  *
19  *      - Redistributions in binary form must reproduce the above
20  *        copyright notice, this list of conditions and the following
21  *        disclaimer in the documentation and/or other materials
22  *        provided with the distribution.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31  * SOFTWARE.
32  *
33  * $Id$
34  */
35  
36 #include "getopt.h"
37 #include "perf_defs.h"
38 #include "get_clock.h"
39
40 #define RC 0
41 #define UC 1
42
43 struct user_parameters {
44         const char              *servername;
45         int connection_type;
46         int mtu;
47         int all; /* run all msg size */
48         int iters;
49         int tx_depth;
50         int numofqps;
51         int maxpostsofqpiniteration;
52 };
53
54 static int page_size;
55
56 cycles_t        *tposted;
57 cycles_t        *tcompleted;
58
59
60 void
61 pp_cq_comp_cb(
62         IN              const   ib_cq_handle_t                          h_cq,
63         IN                              void                                            *cq_context )
64 {
65         UNUSED_PARAM( h_cq );
66         UNUSED_PARAM( cq_context);
67         return ;
68 }
69 static struct pingpong_context *pp_init_ctx(unsigned size, int port, struct user_parameters *user_parm)
70 {
71
72         struct pingpong_context *ctx;
73         ib_api_status_t                         ib_status = IB_SUCCESS; 
74         size_t                                  guid_count;
75         ib_net64_t                              *ca_guid_array;
76         int counter;
77
78         ctx = malloc(sizeof *ctx);
79         if (!ctx){
80                 perror("malloc");
81                 return NULL;
82         }
83         memset(ctx, 0, sizeof(struct pingpong_context));
84         ctx->size = size;
85         ctx->tx_depth = user_parm->tx_depth;
86
87         ctx->qp = malloc(sizeof (ib_qp_handle_t) * user_parm->numofqps );
88         if (!ctx->qp) {
89                 perror("malloc");
90                 return NULL;
91         }
92         ctx->qp_attr = malloc(sizeof (ib_qp_attr_t) * user_parm->numofqps );
93         if (!ctx->qp_attr) {
94                 perror("malloc");
95                 return NULL;
96         }
97
98         ctx->scnt = malloc(user_parm->numofqps * sizeof (int));
99         if (!ctx->scnt) {
100                 perror("malloc");
101                 return NULL;
102         }
103         ctx->ccnt = malloc(user_parm->numofqps * sizeof (int));
104         if (!ctx->ccnt) {
105                 perror("malloc");
106                 return NULL;
107         }
108         memset(ctx->scnt, 0, user_parm->numofqps * sizeof (int));
109         memset(ctx->ccnt, 0, user_parm->numofqps * sizeof (int));
110
111         ctx->buf = malloc( size * 2 * user_parm->numofqps  );
112         if (!ctx->buf) {
113                 fprintf(stderr, "Couldn't allocate work buf.\n");
114                 return NULL;
115         }
116
117         memset(ctx->buf, 0, size * 2 * user_parm->numofqps);
118
119
120
121         /*
122          * Open the AL instance
123          */
124         ib_status = ib_open_al(&ctx->al);
125         if(ib_status != IB_SUCCESS)
126         {
127                 fprintf(stderr,"ib_open_al failed status = %d\n", ib_status);
128                 return NULL;
129         }
130
131         /*
132          * Get the Local CA Guids
133          */
134         ib_status = ib_get_ca_guids(ctx->al, NULL, &guid_count);
135         if(ib_status != IB_INSUFFICIENT_MEMORY)
136         {
137                 fprintf(stderr,"ib_get_ca_guids1 failed status = %d\n", (uint32_t)ib_status);
138                 return NULL;
139         }
140         
141         /*
142          * If no CA's Present then return
143          */
144
145         if(guid_count == 0)
146                 return NULL;
147
148         
149         ca_guid_array = (ib_net64_t*)malloc(sizeof(ib_net64_t) * guid_count);
150         
151         ib_status = ib_get_ca_guids(ctx->al, ca_guid_array, &guid_count);
152         if(ib_status != IB_SUCCESS)
153         {
154                 fprintf(stderr,"ib_get_ca_guids2 failed with status = %d\n", ib_status);
155                 return NULL;
156         }
157
158         /*
159          * Open only the first HCA
160          */
161         /* Open the CA */
162         ib_status = ib_open_ca(ctx->al ,ca_guid_array[0] ,NULL,
163                 NULL,   //ca_context
164                 &ctx->ca);
165
166         if(ib_status != IB_SUCCESS)
167         {
168                 fprintf(stderr,"ib_open_ca failed with status = %d\n", ib_status);
169                 return NULL;
170         }
171
172         //xxx
173         //printf("ib_open_ca passed i=%d\n",i); 
174         //xxx
175
176
177         
178
179         {
180                 /* Query the CA */
181                 uint32_t bsize = 0;
182                 ib_status = ib_query_ca(ctx->ca, NULL, &bsize);
183                 if(ib_status != IB_INSUFFICIENT_MEMORY)
184                 {
185                         fprintf(stderr, "Failed to query device props");
186                         return NULL;
187                 }
188
189                 ctx->ca_attr = (ib_ca_attr_t *)malloc(bsize);
190
191                 ib_status = ib_query_ca(ctx->ca, ctx->ca_attr, &bsize);
192                 if(ib_status != IB_SUCCESS)
193                 {
194                         printf("ib_query_ca failed with status = %d\n", ib_status);
195                         return NULL;
196                 }
197                 if (user_parm->mtu == 0) {/*user did not ask for specific mtu */
198                         if (ctx->ca_attr->dev_id == 23108) {
199                                 user_parm->mtu = 1024;
200                         } else {
201                                 user_parm->mtu = 2048;
202                         }
203                 }
204         }
205
206
207         ib_status = ib_alloc_pd(ctx->ca ,
208                                                 IB_PDT_NORMAL,
209                                                 ctx, //pd_context
210                                                 &ctx->pd);
211         if (ib_status != IB_SUCCESS) {
212                 fprintf(stderr, "Couldn't allocate PD\n");
213                 return NULL;
214         }
215
216
217         {
218                 ib_mr_create_t                  mr_create;
219
220                 mr_create.length = size * 2;
221                         
222                 mr_create.vaddr = ctx->buf;
223                 mr_create.access_ctrl = IB_AC_RDMA_WRITE| IB_AC_LOCAL_WRITE;
224                 
225                 ib_status = ib_reg_mem(ctx->pd ,&mr_create ,&ctx->lkey ,&ctx->rkey ,&ctx->mr);
226                 if (ib_status != IB_SUCCESS) {
227                         fprintf(stderr, "Couldn't allocate MR\n");
228                         return NULL;
229                 }
230         }
231         
232         {
233                 ib_cq_create_t                  cq_create;
234                 
235                 cq_create.size = user_parm->tx_depth * user_parm->numofqps;
236                 cq_create.h_wait_obj = NULL;
237                 cq_create.pfn_comp_cb = pp_cq_comp_cb;
238                 ib_status = ib_create_cq(ctx->ca,&cq_create ,ctx, NULL, &ctx->scq);
239                 if (ib_status != IB_SUCCESS) {
240                         fprintf(stderr, "Couldn't create CQ\n");
241                         return NULL;
242                 }
243         }
244         
245
246
247         
248         for (counter =0 ; counter < user_parm->numofqps ; counter++)
249         {
250
251                 ib_qp_create_t  qp_create;
252                 ib_qp_mod_t     qp_modify;
253                 ib_qp_attr_t    qp_attr;
254                 
255                 memset(&qp_create, 0, sizeof(ib_qp_create_t));
256                 qp_create.h_sq_cq       = ctx->scq;
257                 qp_create.h_rq_cq       = ctx->scq;
258                 qp_create.sq_depth      = user_parm->tx_depth;
259                 qp_create.rq_depth      = user_parm->tx_depth;
260                 qp_create.sq_sge        = 1;
261                 qp_create.rq_sge        = 1;
262                 //TODO MAX_INLINE
263
264                 switch (user_parm->connection_type) {
265                 case RC :
266                         qp_create.qp_type= IB_QPT_RELIABLE_CONN;
267                         break;
268                 case UC :
269                         qp_create.qp_type = IB_QPT_UNRELIABLE_CONN;
270                         break;
271                 default:
272                         fprintf(stderr, "Unknown connection type %d \n",user_parm->connection_type);
273                         return NULL;
274                 }
275                 
276                 qp_create.sq_signaled = FALSE;
277                 /*attr.sq_sig_all = 0;*/
278
279                 ib_status = ib_create_qp(ctx->pd, &qp_create,NULL,NULL,&ctx->qp[counter]);
280                 if (ib_status != IB_SUCCESS){
281                         fprintf(stderr, "Couldn't create QP\n");
282                         return NULL;
283                 }
284         
285
286         
287                 memset(&qp_modify, 0, sizeof(ib_qp_mod_t));
288                 qp_modify.req_state = IB_QPS_INIT;
289                 qp_modify.state.init.pkey_index = 0 ;
290                 qp_modify.state.init.primary_port = (uint8_t)port;
291                 qp_modify.state.init.access_ctrl = IB_AC_RDMA_WRITE | IB_AC_LOCAL_WRITE;
292
293                 
294                 ib_status = ib_modify_qp(ctx->qp[counter], &qp_modify);
295                 if (ib_status != IB_SUCCESS){
296                         fprintf(stderr, "Failed to modify QP to INIT\n");
297                         return NULL;
298                 }
299
300
301                 memset(&qp_attr, 0, sizeof(ib_qp_attr_t));
302                 ib_status = ib_query_qp(ctx->qp[counter], &ctx->qp_attr[counter]);
303                 if (ib_status != IB_SUCCESS){
304                         fprintf(stderr, "Failed to modify QP to INIT\n");
305                         return NULL;
306                 }
307                 fprintf(stderr, "max inline size %d\n",ctx->qp_attr[counter].sq_max_inline);
308         }
309
310         return ctx;
311 }
312
313
314 static int pp_connect_ctx(struct pingpong_context *ctx, int port, int my_psn,
315                           struct pingpong_dest *dest, struct user_parameters *user_parm, int qpindex)
316 {
317
318         ib_api_status_t ib_status;
319         ib_qp_mod_t     attr;
320         memset(&attr, 0, sizeof(ib_qp_mod_t));
321
322         attr.req_state          = IB_QPS_RTR;
323         switch (user_parm->mtu) {
324         case 256 : 
325                 attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_256;
326                 break;
327         case 512 :
328                 attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_512;
329                 break;
330         case 1024 :
331                 attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_1024;
332                 break;
333         case 2048 :
334                 attr.state.rtr.primary_av.conn.path_mtu = IB_MTU_LEN_2048;
335                 break;
336         }
337         printf("Mtu : %d\n", user_parm->mtu);
338         attr.state.rtr.dest_qp  = dest->qpn;;
339         attr.state.rtr.rq_psn   = dest->psn;
340         if (user_parm->connection_type==RC) {
341                 attr.state.rtr.resp_res = 1;
342                 attr.state.rtr.rnr_nak_timeout = 12;
343         }
344         attr.state.rtr.primary_av.grh_valid = 0;
345         attr.state.rtr.primary_av.dlid = dest->lid;
346         attr.state.rtr.primary_av.sl = 0;
347         attr.state.rtr.primary_av.path_bits = 0;
348         attr.state.rtr.primary_av.port_num = (uint8_t)port;
349         attr.state.rtr.primary_av.static_rate = IB_PATH_RECORD_RATE_10_GBS;
350         attr.state.rtr.opts = IB_MOD_QP_LOCAL_ACK_TIMEOUT |
351                                         IB_MOD_QP_RESP_RES |
352                                         IB_MOD_QP_PRIMARY_AV;
353
354
355         ib_status = ib_modify_qp(ctx->qp[qpindex], &attr);
356         if(ib_status != IB_SUCCESS){
357                         fprintf(stderr, "Failed to modify QP to RTR\n");
358                         return 1;
359         }
360
361         memset(&attr, 0, sizeof(ib_qp_mod_t));
362         attr.req_state  = IB_QPS_RTS;
363         attr.state.rts.sq_psn = my_psn;
364
365         if (user_parm->connection_type == RC) {
366                 attr.state.rts.resp_res = 1;
367                 attr.state.rts.local_ack_timeout = 14;
368                 attr.state.rts.retry_cnt = 7;
369                 attr.state.rts.rnr_retry_cnt = 7;
370                 attr.state.rts.opts = IB_MOD_QP_RNR_RETRY_CNT |
371                                                 IB_MOD_QP_RETRY_CNT |
372                                                 IB_MOD_QP_LOCAL_ACK_TIMEOUT;
373                                                 
374         }       
375         ib_status = ib_modify_qp(ctx->qp[qpindex], &attr);
376         if(ib_status != IB_SUCCESS){
377                 fprintf(stderr, "Failed to modify QP to RTS\n");
378                 return 1;
379         }
380
381         return 0;
382
383 }
384
385 static SOCKET pp_open_port(struct pingpong_context *ctx, const char * servername,
386                         int ib_port, int port, struct pingpong_dest **p_my_dest,
387                         struct pingpong_dest **p_rem_dest,struct user_parameters *user_parm)
388 {
389         struct pingpong_dest    *my_dest;
390         struct pingpong_dest    *rem_dest;
391         SOCKET                          sockfd;
392         int                                     rc;
393         int                                     i;
394         int                                     numofqps = user_parm->numofqps;
395         
396         /* Create connection between client and server.
397          * We do it by exchanging data over a TCP socket connection. */
398
399         
400         my_dest = malloc( sizeof (struct pingpong_dest) * numofqps);
401         if (!my_dest){
402                 perror("malloc");
403                 return INVALID_SOCKET;
404         }
405
406         rem_dest = malloc(sizeof (struct pingpong_dest) * numofqps );
407         if (!rem_dest){
408                 perror("malloc");
409                 return INVALID_SOCKET;
410         }
411
412         sockfd = servername ? pp_client_connect(servername, port) :
413                 pp_server_connect(port);
414
415         if (sockfd  == INVALID_SOCKET) {
416                 printf("pp_connect_sock(%s,%d) failed (%d)!\n",
417                        servername, port, sockfd);
418                 return INVALID_SOCKET;
419         }
420
421         
422         for (i =0 ;i<numofqps;i ++) 
423         {
424                 /* Create connection between client and server.
425                 * We do it by exchanging data over a TCP socket connection. */
426                 
427                 my_dest[i].lid = ctx->ca_attr->p_port_attr[ib_port-1].lid;
428                 my_dest[i].psn = rand() & 0xffffff;
429                 if (!my_dest[i].lid) {
430                         fprintf(stderr, "Local lid 0x0 detected. Is an SM running?\n");
431                         return 1;
432                 }
433                 my_dest[i].qpn = ctx->qp_attr[i].num;
434                 /* TBD this should be changed inot VA and different key to each qp */
435                 my_dest[i].rkey = ctx->rkey;
436                 my_dest[i].vaddr = (uintptr_t)ctx->buf + ctx->size;
437
438                 printf("  local address:  LID %#04x, QPN %#06x, PSN %#06x, "
439                 "RKey %#08x VAddr %#016Lx\n",
440                 my_dest[i].lid, my_dest[i].qpn, my_dest[i].psn,
441                 my_dest[i].rkey, my_dest[i].vaddr);
442
443                 rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]):
444                                                 pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]);
445                 if (rc)
446                         return INVALID_SOCKET;
447                 printf("  remote address: LID %#04x, QPN %#06x, PSN %#06x, "
448                 "RKey %#08x VAddr %#016Lx\n",
449                 rem_dest[i].lid, rem_dest[i].qpn, rem_dest[i].psn,
450                 rem_dest[i].rkey, rem_dest[i].vaddr);
451
452                 if (pp_connect_ctx(ctx, ib_port, my_dest[i].psn, &rem_dest[i], user_parm, i))
453                         return INVALID_SOCKET;
454                 /* An additional handshake is required *after* moving qp to RTR.
455                 Arbitrarily reuse exch_dest for this purpose. */
456                 rc = servername ? pp_client_exch_dest(sockfd, &my_dest[i],&rem_dest[i]):
457                                                 pp_server_exch_dest(sockfd, &my_dest[i],&rem_dest[i]);
458                 if (rc)
459                         return INVALID_SOCKET;
460         }
461         *p_rem_dest = rem_dest;
462         *p_my_dest = my_dest;
463         return sockfd;
464 }
465
466
467 static void usage(const char *argv0)
468 {
469         printf("Usage:\n");
470         printf("  %s            start a server and wait for connection\n", argv0);
471         printf("  %s <host>     connect to server at <host>\n", argv0);
472         printf("\n");
473         printf("Options:\n");
474         printf("  -p, --port=<port>         listen on/connect to port <port> (default 18515)\n");
475         printf("  -d, --ib-dev=<dev>        use IB device <dev> (default first device found)\n");
476         printf("  -i, --ib-port=<port>      use port <port> of IB device (default 1)\n");
477         printf("  -c, --connection=<RC/UC>  connection type RC/UC (default RC)\n");
478         printf("  -m, --mtu=<mtu>           mtu size (default 1024)\n");
479         printf("  -g, --post=<num of posts> number of posts for each qp in the chain (default tx_depth)\n");
480         printf("  -q, --qp=<num of qp's>    Num of qp's(default 1)\n");
481         printf("  -s, --size=<size>         size of message to exchange (default 65536)\n");
482         printf("  -a, --all                 Run sizes from 2 till 2^23\n");
483         printf("  -t, --tx-depth=<dep>      size of tx queue (default 100)\n");
484         printf("  -n, --iters=<iters>       number of exchanges (at least 2, default 5000)\n");
485         printf("  -b, --bidirectional       measure bidirectional bandwidth (default unidirectional)\n");
486         printf("  -V, --version             display version number\n");
487 }
488
489 static void 
490         print_report(unsigned int iters, unsigned size, int duplex,
491                          cycles_t *tposted, cycles_t *tcompleted, struct user_parameters *user_param)
492 {
493         double                  cycles_to_units;
494         uint64_t                        tsize;  /* Transferred size, in megabytes */
495         unsigned int            i, j;
496         int                             opt_posted = 0, opt_completed = 0;
497         cycles_t                        opt_delta;
498         cycles_t                        t;
499
500
501         opt_delta = tcompleted[opt_posted] - tposted[opt_completed];
502
503         /* Find the peak bandwidth */
504         for (i = 0; i < iters * user_param->numofqps; ++i)
505                 for (j = i; j < iters * user_param->numofqps; ++j) {
506                         t = (tcompleted[j] - tposted[i]) / (j - i + 1);
507                         if (t < opt_delta) {
508                                 opt_delta  = t;
509                                 opt_posted = i;
510                                 opt_completed = j;
511                         }
512                 }
513
514         
515         cycles_to_units = get_cpu_mhz();
516
517         tsize = duplex ? 2 : 1;
518         tsize = tsize * size;
519         printf("%7d        %d            %7.2f               %7.2f\n",
520                 size,iters,tsize * cycles_to_units / opt_delta / 0x100000,
521                 (uint64_t)tsize * iters * user_param->numofqps * cycles_to_units /(tcompleted[(iters* user_param->numofqps) - 1] - tposted[0]) / 0x100000);
522
523 }
524
525
526 int run_iter(struct pingpong_context *ctx, struct user_parameters *user_param,
527              struct pingpong_dest *rem_dest, int size)
528 {
529         ib_api_status_t         ib_status;
530         ib_qp_handle_t          qp;
531         int                                     scnt, ccnt ;
532         int                                     index;
533         ib_send_wr_t                    *bad_wr;
534
535
536         
537         ctx->list.vaddr = (uintptr_t) ctx->buf;
538         ctx->list.length = size;
539         ctx->list.lkey = ctx->lkey;
540                 
541         ctx->wr.ds_array    = &ctx->list;
542         ctx->wr.num_ds= 1;
543         ctx->wr.wr_type = WR_RDMA_WRITE;
544         
545         if ((uint32_t)size > ctx->qp_attr[0].sq_max_inline) { /*complaince to perf_main */
546                 ctx->wr.send_opt = IB_SEND_OPT_SIGNALED;
547         } else {
548                 ctx->wr.send_opt = IB_SEND_OPT_SIGNALED | IB_SEND_OPT_INLINE;
549         }
550         ctx->wr.p_next = NULL;
551
552         scnt = 0;
553         ccnt = 0;
554         /*clear the scnt ccnt counters for each iteration*/
555         for (index =0 ; index < user_param->numofqps ; index++) {
556                 ctx->scnt[index] = 0;
557                 ctx->ccnt[index] = 0;
558         }
559         index = 0;
560         
561         
562         /* main loop for posting */
563         while (scnt < (user_param->iters * user_param->numofqps) ||
564                 ccnt < (user_param->iters * user_param->numofqps) ) 
565         {
566                 /* main loop to run over all the qps and post each time n messages */
567                 for (index =0 ; index < user_param->numofqps ; index++) {
568
569                         ctx->wr.remote_ops.vaddr = rem_dest[index].vaddr;
570                         ctx->wr.remote_ops.rkey = rem_dest[index].rkey;
571                         qp = ctx->qp[index];
572                         ctx->wr.wr_id      = index ;
573
574                         while (ctx->scnt[index] < user_param->iters && 
575                                 (ctx->scnt[index] - ctx->ccnt[index]) < user_param->maxpostsofqpiniteration)
576                         {
577                                 //if(ctx->scnt[index] - ctx->ccnt[index] < 10 )
578                                 //      fprintf(stderr, "Lower WQEs: qp index = %d qp scnt=%d total scnt %d qp ccnt=%d total ccnt %d\n",
579                                 //      index,ctx->scnt[index],scnt,ctx->ccnt[index],ccnt);
580                                 tposted[scnt] = get_cycles();
581                                 ib_status = ib_post_send(qp, &ctx->wr, &bad_wr);
582                                 if (ib_status != IB_SUCCESS) 
583                                 {
584                                         fprintf(stderr, "Couldn't post send: qp index = %d qp scnt=%d total scnt %d qp ccnt=%d total ccnt %d\n",
585                                         index,ctx->scnt[index],scnt,ctx->ccnt[index],ccnt);
586                                         return 1;
587                                 }
588                                 ctx->scnt[index]= ctx->scnt[index]+1;
589                                 ++scnt;
590                                 PERF_DEBUG("scnt = %d \n",scnt);
591                         }
592
593                 }
594
595                 /* finished posting now polling */
596                 if (ccnt < (user_param->iters * user_param->numofqps) ) 
597                 {
598                         ib_wc_t wc;
599                         ib_wc_t *p_wc_done,*p_wc_free;
600
601                         p_wc_free = &wc;
602                         p_wc_done = NULL;
603                         p_wc_free->p_next = NULL;
604
605                         do{
606                                 ib_status = ib_poll_cq(ctx->scq, &p_wc_free, &p_wc_done);
607                                 if (ib_status == IB_SUCCESS) {
608                                         tcompleted[ccnt] = get_cycles();
609                                         if (p_wc_done->status != IB_WCS_SUCCESS) {
610                                                 fprintf(stderr, "Completion wth error at %s:\n",
611                                                 user_param->servername ? "client" : "server");
612                                                 fprintf(stderr, "Failed status %d: wr_id %d syndrom 0x%x\n",
613                                                 p_wc_done->status, (int) p_wc_done->wr_id, p_wc_done->vendor_specific);
614                                                 return 1;
615                                         }
616
617                                         /*here the id is the index to the qp num */
618                                         ctx->ccnt[(int)wc.wr_id] = ctx->ccnt[(int)wc.wr_id]+1;
619                                         ++ccnt;
620                                         PERF_DEBUG("ccnt = %d \n",ccnt);
621                                         p_wc_free = p_wc_done;
622                                         p_wc_free->p_next = NULL;
623                                         p_wc_done = NULL;
624                                 }
625
626                         
627                         } while (ib_status == IB_SUCCESS);
628
629                         if (ib_status != IB_NOT_FOUND) {
630                                 fprintf(stderr, "Poll Recieve CQ failed %d\n", ib_status);
631                                 return 12;
632                         }
633
634                         
635
636                 }
637         }
638                 return(0);
639 }
640
641
642 int __cdecl main(int argc, char *argv[])
643 {
644         struct pingpong_context *ctx;
645         struct pingpong_dest     *my_dest;
646         struct pingpong_dest     *rem_dest;
647         struct user_parameters  user_param;
648         char                            *ib_devname = NULL;
649         int                             port = 18515;
650         int                             ib_port = 1;
651         unsigned                        size = 65536;
652         SOCKET                  sockfd = INVALID_SOCKET;
653         WSADATA         wsaData;
654         int                             i = 0;
655         int                             iResult; 
656         int                             duplex = 0;
657
658
659         /* init default values to user's parameters */
660         memset(&user_param, 0, sizeof(struct user_parameters));
661         user_param.mtu = 0;
662         user_param.iters = 5000;
663         user_param.tx_depth = 100;
664         user_param.servername = NULL;
665         user_param.numofqps = 1;
666         user_param.maxpostsofqpiniteration = 100;
667
668         /* Parameter parsing. */
669         while (1) {
670                 int c;
671
672                 static struct option long_options[] = {
673                         { "port",                       1,      NULL,   'p' },
674                         { "ib-dev",             1,      NULL,   'd' },
675                         { "ib-port",            1,      NULL,   'i' },
676                         { "mtu",                        1,      NULL,   'm' },
677                         { "qp",                 1,      NULL,   'q' },
678                         { "post",                       1,      NULL,   'g' },
679                         { "connection", 1,      NULL,   'c' },
680                         { "size",                       1,      NULL,   's' },
681                         { "iters",                      1,      NULL,   'n' },
682                         { "tx-depth",           1,      NULL,   't' },
683                         { "all",                        0,      NULL,   'a' },
684                         { "bidirectional",      0,      NULL,   'b' },
685                         { "version",            0,      NULL,   'V' },
686                         { 0 }
687                 };
688
689                 c = getopt_long(argc, argv, "p:d:i:m:q:g:c:s:n:t:baV", long_options, NULL);
690                 if (c == -1)
691                         break;
692
693                 switch (c) {
694                 case 'p':
695                         port = strtol(optarg, NULL, 0);
696                         if (port < 0 || port > 65535) {
697                                 usage(argv[0]);
698                                 return 1;
699                         }
700                         break;
701
702                 case 'd':
703                         ib_devname = _strdup(optarg);
704                         break;
705                 case 'c':
706                         if (strcmp("UC",optarg)==0)
707                                 user_param.connection_type=UC;
708                         break;
709
710                 case 'm':
711                         user_param.mtu = strtol(optarg, NULL, 0);
712                         break;
713                 case 'q':
714                         user_param.numofqps = strtol(optarg, NULL, 0);
715                         break;
716                 case 'g':
717                         user_param.maxpostsofqpiniteration = strtol(optarg, NULL, 0);
718                         break;
719                 case 'a':
720                         user_param.all = ALL;
721                         break;
722                 case 'V':
723                         printf("rdma_bw version : %.2f\n",VERSION);
724                         return 0;
725                         break;
726                 case 'i':
727                         ib_port = strtol(optarg, NULL, 0);
728                         if (ib_port < 0) {
729                                 usage(argv[0]);
730                                 return 1;
731                         }
732                         break;
733
734                 case 's':
735                         size = strtol(optarg, NULL, 0);
736                         if (size < 1 || size > UINT_MAX / 2) {
737                                 usage(argv[0]);
738                                 return 1;
739                         }
740                         break;
741
742                 case 't':
743                         user_param.tx_depth = strtol(optarg, NULL, 0);
744                         if (user_param.tx_depth < 1) { usage(argv[0]); return 1; }
745                         break;
746
747                 case 'n':
748                         user_param.iters = strtol(optarg, NULL, 0);
749                         if (user_param.iters < 2) {
750                                 usage(argv[0]);
751                                 return 1;
752                         }
753
754                         break;
755
756                 case 'b':
757                         duplex = 1;
758                         break;
759
760                 default:
761                         usage(argv[0]);
762                         return 1;
763                 }
764         }
765
766         if (optind == argc - 1)
767                 user_param.servername = _strdup(argv[optind]);
768         else if (optind < argc) {
769                 usage(argv[0]);
770                 return 1;
771         }
772         
773         printf("------------------------------------------------------------------\n");
774         if (duplex == 1) {
775           printf("                    RDMA_Write Bidirectional BW Test\n");
776         } else {
777           printf("                    RDMA_Write BW Test\n");
778         }
779         
780         printf("Inline data is used up to 400 bytes message\n");
781         printf("Number of qp's running          %d\n",user_param.numofqps);
782         printf("Number of iterations                    %d\n",user_param.iters);
783         printf("Massege size                            %d\n",size);
784         if (user_param.connection_type==RC) {
785                 printf("Connection type : RC\n");
786         } else {
787                 printf("Connection type : UC\n");
788         }
789         if (user_param.maxpostsofqpiniteration > user_param.tx_depth ) {
790           printf("Can not post more than tx_depth , adjusting number of post to tx_depth\n");
791           user_param.maxpostsofqpiniteration = user_param.tx_depth;
792         } else {
793           printf("Each Qp will post up to %d messages each time\n",user_param.maxpostsofqpiniteration);
794         }
795         /* Done with parameter parsing. Perform setup. */
796
797         // Initialize Winsock
798         iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
799         if (iResult != NO_ERROR) {
800                 printf("Error at WSAStartup()\n");
801                 return 1;
802         }
803
804         
805         if (user_param.all == ALL) {
806                 /*since we run all sizes */
807                 size = 8388608; /*2^23 */
808         }
809         
810         srand(GetCurrentProcessId() * GetTickCount());
811
812         //TODO: get pagesize from sysinfo
813         page_size = 4096;
814
815         //TODO:get the device names
816
817
818         ctx = pp_init_ctx(size, ib_port, &user_param);
819         if (!ctx)
820                 return 1;
821
822         sockfd = pp_open_port(ctx, user_param.servername, ib_port, port,&my_dest,&rem_dest,&user_param);
823         if (sockfd == INVALID_SOCKET)
824                 return 9;
825         
826         
827         printf("------------------------------------------------------------------\n");
828         printf(" #bytes #iterations    BW peak[MB/sec]    BW average[MB/sec]  \n");
829         /* For half duplex tests, server just waits for client to exit */
830         /* use dummy my_dest struct*/
831         if (!user_param.servername && !duplex) {
832                 pp_server_exch_dest(sockfd, my_dest,rem_dest);
833                 send(sockfd, "done", sizeof "done",0);
834                 closesocket(sockfd);
835                 return 0;
836         }
837
838         tposted = malloc(user_param.iters * user_param.numofqps * sizeof *tposted);
839
840         if (!tposted) {
841                 perror("malloc");
842                 return 1;
843         }
844
845         tcompleted = malloc(user_param.iters * user_param.numofqps * sizeof *tcompleted);
846
847         if (!tcompleted) {
848                 perror("malloc");
849                 return 1;
850         }
851
852         if (user_param.all == ALL) {
853                 for (i = 1; i < 24 ; ++i) {
854                         size = 1 << i;
855                         if(run_iter(ctx, &user_param, rem_dest, size))
856                                 return 17;
857                         print_report(user_param.iters, size, duplex, tposted, tcompleted, &user_param);
858                 }
859         } else {
860                         if(run_iter(ctx, &user_param, rem_dest, size))
861                                 return 18;
862                         print_report(user_param.iters, size, duplex, tposted, tcompleted, &user_param);
863
864         }
865
866         /* use dummy my_dest struct*/
867         if (user_param.servername) {
868                 pp_client_exch_dest(sockfd, my_dest,rem_dest);
869         } else {
870                 pp_server_exch_dest(sockfd, my_dest,rem_dest);
871         }
872         send(sockfd, "done", sizeof "done",0);
873         closesocket(sockfd);
874         
875         free(tposted);
876         free(tcompleted);
877         printf("------------------------------------------------------------------\n");
878         return 0;
879 }