Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Reduce the size of partial shared malloc tests.
[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"))
31         verbose = 1;
32
33     MPI_Comm_size(MPI_COMM_WORLD, &wsize);
34     MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
35
36     if (wsize < 2) {
37         fprintf(stderr, "This program requires at least 2 processes\n");
38         MPI_Abort(MPI_COMM_WORLD, 1);
39     }
40     /* Set partner based on whether rank is odd or even */
41     if (wrank & 0x1) {
42         partner = wrank - 1;
43     }
44     else if (wrank < wsize - 1) {
45         partner = wrank + 1;
46     }
47     else
48         /* Handle wsize odd */
49         partner = MPI_PROC_NULL;
50
51     /* Allocate and initialize buffers */
52     maxlen = 1024 * 1024;
53     rbuf = (char *) malloc(maxlen);
54     sbuf = (char *) malloc(maxlen);
55     if (!rbuf || !sbuf) {
56         fprintf(stderr, "Could not allocate %d byte buffers\n", maxlen);
57         MPI_Abort(MPI_COMM_WORLD, 2);
58     }
59     for (k = 0; k < maxlen; k++) {
60         rbuf[k] = 0;
61         sbuf[k] = 0;
62     }
63
64     MPI_Barrier(MPI_COMM_WORLD);
65
66     /* Test Irecv and send, head to head */
67     if (wrank == 0 && verbose) {
68         printf("Irecv-send\n");
69         printf("len\ttime    \trate\n");
70     }
71
72     /* Send powers of 2 bytes */
73     len = 1;
74     for (k = 0; k < 20; k++) {
75         /* We use a simple linear form for the number of tests to
76          * reduce the impact of the granularity of the timer */
77         reps = 50 - k;
78         repsleft = reps;
79         /* Make sure that both processes are ready to start */
80         MPI_Sendrecv(MPI_BOTTOM, 0, MPI_BYTE, partner, 0,
81                      MPI_BOTTOM, 0, MPI_BYTE, partner, 0, MPI_COMM_WORLD, 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, MPI_STATUS_IGNORE);
127         t1 = MPI_Wtime();
128         while (repsleft--) {
129             MPI_Sendrecv(sbuf, len, MPI_BYTE, partner, k,
130                          rbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
131         }
132         t1 = MPI_Wtime() - t1;
133         times[1][k] = t1 / reps;
134         if (wrank == 0) {
135             t1 = t1 / reps;
136             if (t1 > 0) {
137                 t1 = t1 * 1.e6;
138                 if (verbose)
139                     printf("%d\t%g\t%g\n", len, t1, len / t1);
140             }
141             else {
142                 t1 = t1 * 1.e6;
143                 if (verbose)
144                     printf("%d\t%g\tINF\n", len, t1);
145             }
146             if (verbose)
147                 fflush(stdout);
148         }
149
150         len *= 2;
151     }
152
153     MPI_Barrier(MPI_COMM_WORLD);
154
155     /* Test Send/recv, ping-pong */
156     if (wrank == 0 && verbose) {
157         printf("Pingpong\n");
158         printf("len\ttime (usec)\trate (MB/s)\n");
159     }
160
161     /* Send powers of 2 bytes */
162     len = 1;
163     for (k = 0; k < 20; k++) {
164         /* We use a simple linear form for the number of tests to
165          * reduce the impact of the granularity of the timer */
166         reps = 50 - k;
167         repsleft = reps;
168         /* Make sure that both processes are ready to start */
169         MPI_Sendrecv(MPI_BOTTOM, 0, MPI_BYTE, partner, 0,
170                      MPI_BOTTOM, 0, MPI_BYTE, partner, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
171         t1 = MPI_Wtime();
172         while (repsleft--) {
173             if (wrank & 0x1) {
174                 MPI_Send(sbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD);
175                 MPI_Recv(rbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
176             }
177             else {
178                 MPI_Recv(rbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
179                 MPI_Send(sbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD);
180             }
181         }
182         t1 = MPI_Wtime() - t1;
183         times[2][k] = t1 / reps;
184         if (wrank == 0) {
185             t1 = t1 / reps;
186             if (t1 > 0) {
187                 t1 = t1 * 1.e6;
188                 if (verbose)
189                     printf("%d\t%g\t%g\n", len, t1, len / t1);
190             }
191             else {
192                 t1 = t1 * 1.e6;
193                 if (verbose)
194                     printf("%d\t%g\tINF\n", len, t1);
195             }
196             if (verbose)
197                 fflush(stdout);
198         }
199
200         len *= 2;
201     }
202
203
204     /* At this point, we could optionally analyze the results and report
205      * success or failure based on some criteria, such as near monotone
206      * increases in bandwidth.  This test was created because of a
207      * fall-off in performance noted in the ch3:sock device:channel */
208
209     if (wrank == 0) {
210         int nPerfErrors = 0;
211         len = 1;
212         for (k = 0; k < 20; k++) {
213             double T0, T1, T2;
214             T0 = times[0][k] * 1.e6;
215             T1 = times[1][k] * 1.e6;
216             T2 = times[2][k] * 1.e6;
217             if (verbose)
218                 printf("%d\t%12.2f\t%12.2f\t%12.2f\n", len, T0, T1, T2);
219             /* Lets look at long messages only */
220             if (k > 10) {
221                 double T0Old, T1Old, T2Old;
222                 T0Old = times[0][k - 1] * 1.0e6;
223                 T1Old = times[1][k - 1] * 1.0e6;
224                 T2Old = times[2][k - 1] * 1.0e6;
225                 if (T0 > (2 + ERROR_MARGIN) * T0Old) {
226                     nPerfErrors++;
227                     if (verbose)
228                         printf("Irecv-Send:\t%d\t%12.2f\t%12.2f\n", len, T0Old, T0);
229                 }
230                 if (T1 > (2 + ERROR_MARGIN) * T1Old) {
231                     nPerfErrors++;
232                     if (verbose)
233                         printf("Sendrecv:\t%d\t%12.2f\t%12.2f\n", len, T1Old, T1);
234                 }
235                 if (T2 > (2 + ERROR_MARGIN) * T2Old) {
236                     nPerfErrors++;
237                     if (verbose)
238                         printf("Pingpong:\t%d\t%12.2f\t%12.2f\n", len, T2Old, T2);
239                 }
240             }
241             len *= 2;
242         }
243         if (nPerfErrors > 8) {
244             /* Allow for 1-2 errors for eager-rendezvous shifting
245              * point and cache effects. There should be a better way
246              * of doing this. */
247             printf(" Found %d performance errors\n", nPerfErrors);
248         }
249         else {
250             printf(" No Errors\n");
251         }
252         fflush(stdout);
253     }
254
255     free(sbuf);
256     free(rbuf);
257
258     MPI_Finalize();
259
260     return 0;
261 }