Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'mc'
[simgrid.git] / teshsuite / smpi / mpich3-test / perf / sendrecvl.c
1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2 /*
3  *  (C) 2006 by Argonne National Laboratory.
4  *      See COPYRIGHT in top-level directory.
5  */
6
7 /* This program provides a simple test of send-receive performance between
8    two (or more) processes.  This sometimes called head-to-head or
9    ping-ping test, as both processes send at the same time.
10 */
11
12 #include "mpi.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15
16 #define MAXTESTS 32
17 #define ERROR_MARGIN 1.0 /* FIXME: This number is pretty much randomly chosen */
18
19 static int verbose = 0;
20
21 int main( int argc, char *argv[] )
22 {
23     int wsize, wrank, partner, len, maxlen, k, reps, repsleft;
24     double t1;
25     MPI_Request rreq;
26     char *rbuf, *sbuf;
27     double times[3][MAXTESTS];
28
29     MPI_Init( &argc, &argv );
30     if (getenv("MPITEST_VERBOSE")) verbose = 1;
31
32     MPI_Comm_size( MPI_COMM_WORLD, &wsize );
33     MPI_Comm_rank( MPI_COMM_WORLD, &wrank );
34     
35     if (wsize < 2) {
36         fprintf( stderr, "This program requires at least 2 processes\n" );
37         MPI_Abort( MPI_COMM_WORLD, 1 );
38     }
39     /* Set partner based on whether rank is odd or even */
40     if (wrank & 0x1) {
41         partner = wrank - 1;
42     }
43     else if (wrank < wsize - 1) {
44         partner = wrank + 1;
45     }
46     else 
47         /* Handle wsize odd */
48         partner = MPI_PROC_NULL;
49
50     /* Allocate and initialize buffers */
51     maxlen = 1024*1024;
52     rbuf = (char *)malloc( maxlen );
53     sbuf = (char *)malloc( maxlen );
54     if (!rbuf || !sbuf) {
55         fprintf( stderr, "Could not allocate %d byte buffers\n", maxlen );
56         MPI_Abort( MPI_COMM_WORLD, 2 );
57     }
58     for (k=0; k<maxlen; k++) {
59         rbuf[k] = 0;
60         sbuf[k] = 0;
61     }
62     
63     MPI_Barrier( MPI_COMM_WORLD );
64
65     /* Test Irecv and send, head to head */
66     if (wrank == 0 && verbose) {
67         printf( "Irecv-send\n" );
68         printf( "len\ttime    \trate\n" );
69     }
70
71     /* Send powers of 2 bytes */
72     len = 1;
73     for (k=0; k<20; k++) {
74         /* We use a simple linear form for the number of tests to 
75            reduce the impact of the granularity of the timer */
76         reps     = 50-k;
77         repsleft = reps;
78         /* Make sure that both processes are ready to start */
79         MPI_Sendrecv( MPI_BOTTOM, 0, MPI_BYTE, partner, 0, 
80                       MPI_BOTTOM, 0, MPI_BYTE, partner, 0, MPI_COMM_WORLD, 
81                       MPI_STATUS_IGNORE );
82         t1 = MPI_Wtime();
83         while (repsleft--) {
84             MPI_Irecv( rbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD, &rreq );
85             MPI_Send( sbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD );
86             MPI_Wait( &rreq, MPI_STATUS_IGNORE );
87         }
88         t1 = MPI_Wtime() - t1;
89         times[0][k] = t1 / reps;
90         if (wrank == 0) {
91             t1 = t1 / reps;
92             if (t1 > 0) {
93                 double rate;
94                 rate = (len / t1) / 1.e6;
95                 t1   = t1 * 1.e6;
96                 if (verbose) 
97                     printf( "%d\t%g\t%g\n", len, t1, len/t1 );
98             }
99             else {
100                 t1   = t1 * 1.e6;
101                 if (verbose)
102                     printf( "%d\t%g\tINF\n", len, t1 );
103             }
104             if (verbose)
105                 fflush( stdout );
106         }
107
108         len *= 2;
109     }
110
111     MPI_Barrier( MPI_COMM_WORLD );
112
113     /* Test Sendrecv, head to head */
114     if (wrank == 0 && verbose) {
115         printf( "Sendrecv\n" );
116         printf( "len\ttime (usec)\trate (MB/s)\n" );
117     }
118
119     /* Send powers of 2 bytes */
120     len = 1;
121     for (k=0; k<20; k++) {
122         /* We use a simple linear form for the number of tests to 
123            reduce the impact of the granularity of the timer */
124         reps     = 50-k;
125         repsleft = reps;
126         /* Make sure that both processes are ready to start */
127         MPI_Sendrecv( MPI_BOTTOM, 0, MPI_BYTE, partner, 0, 
128                       MPI_BOTTOM, 0, MPI_BYTE, partner, 0, MPI_COMM_WORLD, 
129                       MPI_STATUS_IGNORE );
130         t1 = MPI_Wtime();
131         while (repsleft--) {
132             MPI_Sendrecv( sbuf, len, MPI_BYTE, partner, k, 
133                           rbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD,
134                           MPI_STATUS_IGNORE );
135         }
136         t1 = MPI_Wtime() - t1;
137         times[1][k] = t1 / reps;
138         if (wrank == 0) {
139             t1 = t1 / reps;
140             if (t1 > 0) {
141                 double rate;
142                 rate = (len / t1) / 1.e6;
143                 t1   = t1 * 1.e6;
144                 if (verbose)
145                     printf( "%d\t%g\t%g\n", len, t1, len/t1 );
146             }
147             else {
148                 t1   = t1 * 1.e6;
149                 if (verbose)
150                     printf( "%d\t%g\tINF\n", len, t1 );
151             }
152             if (verbose)
153                 fflush( stdout );
154         }
155
156         len *= 2;
157     }
158
159     MPI_Barrier( MPI_COMM_WORLD );
160
161     /* Test Send/recv, ping-pong */
162     if (wrank == 0 && verbose) {
163         printf( "Pingpong\n" );
164         printf( "len\ttime (usec)\trate (MB/s)\n" );
165     }
166
167     /* Send powers of 2 bytes */
168     len = 1;
169     for (k=0; k<20; k++) {
170         /* We use a simple linear form for the number of tests to 
171            reduce the impact of the granularity of the timer */
172         reps     = 50-k;
173         repsleft = reps;
174         /* Make sure that both processes are ready to start */
175         MPI_Sendrecv( MPI_BOTTOM, 0, MPI_BYTE, partner, 0, 
176                       MPI_BOTTOM, 0, MPI_BYTE, partner, 0, MPI_COMM_WORLD, 
177                       MPI_STATUS_IGNORE );
178         t1 = MPI_Wtime();
179         while (repsleft--) {
180             if (wrank & 0x1) {
181                 MPI_Send( sbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD );
182                 MPI_Recv( rbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD, 
183                           MPI_STATUS_IGNORE );
184             }
185             else {
186                 MPI_Recv( rbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD, 
187                           MPI_STATUS_IGNORE );
188                 MPI_Send( sbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD );
189             }
190         }
191         t1 = MPI_Wtime() - t1;
192         times[2][k] = t1 / reps;
193         if (wrank == 0) {
194             t1 = t1 / reps;
195             if (t1 > 0) {
196                 double rate;
197                 rate = (len / t1) / 1.e6;
198                 t1   = t1 * 1.e6;
199                 if (verbose)
200                     printf( "%d\t%g\t%g\n", len, t1, len/t1 );
201             }
202             else {
203                 t1   = t1 * 1.e6;
204                 if (verbose)
205                     printf( "%d\t%g\tINF\n", len, t1 );
206             }
207             if (verbose)
208                 fflush( stdout );
209         }
210
211         len *= 2;
212     }
213     
214     
215     /* At this point, we could optionally analyze the results and report
216        success or failure based on some criteria, such as near monotone
217        increases in bandwidth.  This test was created because of a 
218        fall-off in performance noted in the ch3:sock device:channel */
219
220     if (wrank == 0) {
221         int nPerfErrors = 0;
222         len = 1;
223         for (k=0; k<20; k++) {
224             double T0,T1,T2;
225             T0 = times[0][k] * 1.e6;
226             T1 = times[1][k] * 1.e6;
227             T2 = times[2][k] * 1.e6;
228             if (verbose)
229                 printf( "%d\t%12.2f\t%12.2f\t%12.2f\n", len, T0, T1, T2 );
230             /* Lets look at long messages only */
231             if (k > 10) {
232                 double T0Old, T1Old, T2Old;
233                 T0Old = times[0][k-1] * 1.0e6;
234                 T1Old = times[1][k-1] * 1.0e6;
235                 T2Old = times[2][k-1] * 1.0e6;
236                 if (T0 > (2+ERROR_MARGIN) * T0Old) {
237                     nPerfErrors++;
238                     if (verbose)
239                         printf( "Irecv-Send:\t%d\t%12.2f\t%12.2f\n", len, T0Old, T0 );
240                 }
241                 if (T1 > (2+ERROR_MARGIN) * T1Old) {
242                     nPerfErrors++;
243                     if (verbose)
244                         printf( "Sendrecv:\t%d\t%12.2f\t%12.2f\n", len, T1Old, T1 );
245                 }
246                 if (T2 > (2+ERROR_MARGIN) * T2Old) {
247                     nPerfErrors++;
248                     if (verbose)
249                         printf( "Pingpong:\t%d\t%12.2f\t%12.2f\n", len, T2Old, T2 );
250                 }
251             }
252             len *= 2;
253         }
254         if (nPerfErrors > 8) { 
255             /* Allow for 1-2 errors for eager-rendezvous shifting
256              * point and cache effects. There should be a better way
257              * of doing this. */
258             printf( " Found %d performance errors\n", nPerfErrors );
259         }
260         else {
261             printf( " No Errors\n" );
262         }
263         fflush( stdout );
264     }
265
266     free( sbuf );
267     free( rbuf );
268
269     MPI_Finalize();
270
271     return 0;
272 }