Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of scm.gforge.inria.fr:/gitroot/simgrid/simgrid
[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                 t1   = t1 * 1.e6;
94                 if (verbose) 
95                     printf( "%d\t%g\t%g\n", len, t1, len/t1 );
96             }
97             else {
98                 t1   = t1 * 1.e6;
99                 if (verbose)
100                     printf( "%d\t%g\tINF\n", len, t1 );
101             }
102             if (verbose)
103                 fflush( stdout );
104         }
105
106         len *= 2;
107     }
108
109     MPI_Barrier( MPI_COMM_WORLD );
110
111     /* Test Sendrecv, head to head */
112     if (wrank == 0 && verbose) {
113         printf( "Sendrecv\n" );
114         printf( "len\ttime (usec)\trate (MB/s)\n" );
115     }
116
117     /* Send powers of 2 bytes */
118     len = 1;
119     for (k=0; k<20; k++) {
120         /* We use a simple linear form for the number of tests to 
121            reduce the impact of the granularity of the timer */
122         reps     = 50-k;
123         repsleft = reps;
124         /* Make sure that both processes are ready to start */
125         MPI_Sendrecv( MPI_BOTTOM, 0, MPI_BYTE, partner, 0, 
126                       MPI_BOTTOM, 0, MPI_BYTE, partner, 0, MPI_COMM_WORLD, 
127                       MPI_STATUS_IGNORE );
128         t1 = MPI_Wtime();
129         while (repsleft--) {
130             MPI_Sendrecv( sbuf, len, MPI_BYTE, partner, k, 
131                           rbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD,
132                           MPI_STATUS_IGNORE );
133         }
134         t1 = MPI_Wtime() - t1;
135         times[1][k] = t1 / reps;
136         if (wrank == 0) {
137             t1 = t1 / reps;
138             if (t1 > 0) {
139                 t1   = t1 * 1.e6;
140                 if (verbose)
141                     printf( "%d\t%g\t%g\n", len, t1, len/t1 );
142             }
143             else {
144                 t1   = t1 * 1.e6;
145                 if (verbose)
146                     printf( "%d\t%g\tINF\n", len, t1 );
147             }
148             if (verbose)
149                 fflush( stdout );
150         }
151
152         len *= 2;
153     }
154
155     MPI_Barrier( MPI_COMM_WORLD );
156
157     /* Test Send/recv, ping-pong */
158     if (wrank == 0 && verbose) {
159         printf( "Pingpong\n" );
160         printf( "len\ttime (usec)\trate (MB/s)\n" );
161     }
162
163     /* Send powers of 2 bytes */
164     len = 1;
165     for (k=0; k<20; k++) {
166         /* We use a simple linear form for the number of tests to 
167            reduce the impact of the granularity of the timer */
168         reps     = 50-k;
169         repsleft = reps;
170         /* Make sure that both processes are ready to start */
171         MPI_Sendrecv( MPI_BOTTOM, 0, MPI_BYTE, partner, 0, 
172                       MPI_BOTTOM, 0, MPI_BYTE, partner, 0, MPI_COMM_WORLD, 
173                       MPI_STATUS_IGNORE );
174         t1 = MPI_Wtime();
175         while (repsleft--) {
176             if (wrank & 0x1) {
177                 MPI_Send( sbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD );
178                 MPI_Recv( rbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD, 
179                           MPI_STATUS_IGNORE );
180             }
181             else {
182                 MPI_Recv( rbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD, 
183                           MPI_STATUS_IGNORE );
184                 MPI_Send( sbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD );
185             }
186         }
187         t1 = MPI_Wtime() - t1;
188         times[2][k] = t1 / reps;
189         if (wrank == 0) {
190             t1 = t1 / reps;
191             if (t1 > 0) {
192                 t1   = t1 * 1.e6;
193                 if (verbose)
194                     printf( "%d\t%g\t%g\n", len, t1, len/t1 );
195             }
196             else {
197                 t1   = t1 * 1.e6;
198                 if (verbose)
199                     printf( "%d\t%g\tINF\n", len, t1 );
200             }
201             if (verbose)
202                 fflush( stdout );
203         }
204
205         len *= 2;
206     }
207     
208     
209     /* At this point, we could optionally analyze the results and report
210        success or failure based on some criteria, such as near monotone
211        increases in bandwidth.  This test was created because of a 
212        fall-off in performance noted in the ch3:sock device:channel */
213
214     if (wrank == 0) {
215         int nPerfErrors = 0;
216         len = 1;
217         for (k=0; k<20; k++) {
218             double T0,T1,T2;
219             T0 = times[0][k] * 1.e6;
220             T1 = times[1][k] * 1.e6;
221             T2 = times[2][k] * 1.e6;
222             if (verbose)
223                 printf( "%d\t%12.2f\t%12.2f\t%12.2f\n", len, T0, T1, T2 );
224             /* Lets look at long messages only */
225             if (k > 10) {
226                 double T0Old, T1Old, T2Old;
227                 T0Old = times[0][k-1] * 1.0e6;
228                 T1Old = times[1][k-1] * 1.0e6;
229                 T2Old = times[2][k-1] * 1.0e6;
230                 if (T0 > (2+ERROR_MARGIN) * T0Old) {
231                     nPerfErrors++;
232                     if (verbose)
233                         printf( "Irecv-Send:\t%d\t%12.2f\t%12.2f\n", len, T0Old, T0 );
234                 }
235                 if (T1 > (2+ERROR_MARGIN) * T1Old) {
236                     nPerfErrors++;
237                     if (verbose)
238                         printf( "Sendrecv:\t%d\t%12.2f\t%12.2f\n", len, T1Old, T1 );
239                 }
240                 if (T2 > (2+ERROR_MARGIN) * T2Old) {
241                     nPerfErrors++;
242                     if (verbose)
243                         printf( "Pingpong:\t%d\t%12.2f\t%12.2f\n", len, T2Old, T2 );
244                 }
245             }
246             len *= 2;
247         }
248         if (nPerfErrors > 8) { 
249             /* Allow for 1-2 errors for eager-rendezvous shifting
250              * point and cache effects. There should be a better way
251              * of doing this. */
252             printf( " Found %d performance errors\n", nPerfErrors );
253         }
254         else {
255             printf( " No Errors\n" );
256         }
257         fflush( stdout );
258     }
259
260     free( sbuf );
261     free( rbuf );
262
263     MPI_Finalize();
264
265     return 0;
266 }