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