|
Packit Service |
c5cf8c |
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
|
Packit Service |
c5cf8c |
/*
|
|
Packit Service |
c5cf8c |
* (C) 2006 by Argonne National Laboratory.
|
|
Packit Service |
c5cf8c |
* See COPYRIGHT in top-level directory.
|
|
Packit Service |
c5cf8c |
*/
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* This program provides a simple test of send-receive performance between
|
|
Packit Service |
c5cf8c |
two (or more) processes. This sometimes called head-to-head or
|
|
Packit Service |
c5cf8c |
ping-ping test, as both processes send at the same time.
|
|
Packit Service |
c5cf8c |
*/
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
#include "mpi.h"
|
|
Packit Service |
c5cf8c |
#include <stdio.h>
|
|
Packit Service |
c5cf8c |
#include <stdlib.h>
|
|
Packit Service |
c5cf8c |
#include "mpitest.h"
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
#define MAXTESTS 32
|
|
Packit Service |
c5cf8c |
#define ERROR_MARGIN 1.0 /* FIXME: This number is pretty much randomly chosen */
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
static int verbose = 0;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
int main(int argc, char *argv[])
|
|
Packit Service |
c5cf8c |
{
|
|
Packit Service |
c5cf8c |
int wsize, wrank, partner, len, maxlen, k, reps, repsleft;
|
|
Packit Service |
c5cf8c |
double t1;
|
|
Packit Service |
c5cf8c |
MPI_Request rreq;
|
|
Packit Service |
c5cf8c |
char *rbuf, *sbuf;
|
|
Packit Service |
c5cf8c |
double times[3][MAXTESTS];
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MTest_Init(&argc, &argv);
|
|
Packit Service |
c5cf8c |
if (getenv("MPITEST_VERBOSE"))
|
|
Packit Service |
c5cf8c |
verbose = 1;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Comm_size(MPI_COMM_WORLD, &wsize);
|
|
Packit Service |
c5cf8c |
MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
if (wsize < 2) {
|
|
Packit Service |
c5cf8c |
fprintf(stderr, "This program requires at least 2 processes\n");
|
|
Packit Service |
c5cf8c |
MPI_Abort(MPI_COMM_WORLD, 1);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
/* Set partner based on whether rank is odd or even */
|
|
Packit Service |
c5cf8c |
if (wrank & 0x1) {
|
|
Packit Service |
c5cf8c |
partner = wrank - 1;
|
|
Packit Service |
c5cf8c |
} else if (wrank < wsize - 1) {
|
|
Packit Service |
c5cf8c |
partner = wrank + 1;
|
|
Packit Service |
c5cf8c |
} else
|
|
Packit Service |
c5cf8c |
/* Handle wsize odd */
|
|
Packit Service |
c5cf8c |
partner = MPI_PROC_NULL;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Allocate and initialize buffers */
|
|
Packit Service |
c5cf8c |
maxlen = 1024 * 1024;
|
|
Packit Service |
c5cf8c |
rbuf = (char *) malloc(maxlen);
|
|
Packit Service |
c5cf8c |
sbuf = (char *) malloc(maxlen);
|
|
Packit Service |
c5cf8c |
if (!rbuf || !sbuf) {
|
|
Packit Service |
c5cf8c |
fprintf(stderr, "Could not allocate %d byte buffers\n", maxlen);
|
|
Packit Service |
c5cf8c |
MPI_Abort(MPI_COMM_WORLD, 2);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
for (k = 0; k < maxlen; k++) {
|
|
Packit Service |
c5cf8c |
rbuf[k] = 0;
|
|
Packit Service |
c5cf8c |
sbuf[k] = 0;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Barrier(MPI_COMM_WORLD);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Test Irecv and send, head to head */
|
|
Packit Service |
c5cf8c |
if (wrank == 0 && verbose) {
|
|
Packit Service |
c5cf8c |
printf("Irecv-send\n");
|
|
Packit Service |
c5cf8c |
printf("len\ttime \trate\n");
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Send powers of 2 bytes */
|
|
Packit Service |
c5cf8c |
len = 1;
|
|
Packit Service |
c5cf8c |
for (k = 0; k < 20; k++) {
|
|
Packit Service |
c5cf8c |
/* We use a simple linear form for the number of tests to
|
|
Packit Service |
c5cf8c |
* reduce the impact of the granularity of the timer */
|
|
Packit Service |
c5cf8c |
reps = 50 - k;
|
|
Packit Service |
c5cf8c |
repsleft = reps;
|
|
Packit Service |
c5cf8c |
/* Make sure that both processes are ready to start */
|
|
Packit Service |
c5cf8c |
MPI_Sendrecv(MPI_BOTTOM, 0, MPI_BYTE, partner, 0,
|
|
Packit Service |
c5cf8c |
MPI_BOTTOM, 0, MPI_BYTE, partner, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
|
|
Packit Service |
c5cf8c |
t1 = MPI_Wtime();
|
|
Packit Service |
c5cf8c |
while (repsleft--) {
|
|
Packit Service |
c5cf8c |
MPI_Irecv(rbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD, &rreq);
|
|
Packit Service |
c5cf8c |
MPI_Send(sbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD);
|
|
Packit Service |
c5cf8c |
MPI_Wait(&rreq, MPI_STATUS_IGNORE);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
t1 = MPI_Wtime() - t1;
|
|
Packit Service |
c5cf8c |
times[0][k] = t1 / reps;
|
|
Packit Service |
c5cf8c |
if (wrank == 0) {
|
|
Packit Service |
c5cf8c |
t1 = t1 / reps;
|
|
Packit Service |
c5cf8c |
if (t1 > 0) {
|
|
Packit Service |
c5cf8c |
double rate;
|
|
Packit Service |
c5cf8c |
rate = (len / t1) / 1.e6;
|
|
Packit Service |
c5cf8c |
t1 = t1 * 1.e6;
|
|
Packit Service |
c5cf8c |
if (verbose)
|
|
Packit Service |
c5cf8c |
printf("%d\t%g\t%g\n", len, t1, len / t1);
|
|
Packit Service |
c5cf8c |
} else {
|
|
Packit Service |
c5cf8c |
t1 = t1 * 1.e6;
|
|
Packit Service |
c5cf8c |
if (verbose)
|
|
Packit Service |
c5cf8c |
printf("%d\t%g\tINF\n", len, t1);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
if (verbose)
|
|
Packit Service |
c5cf8c |
fflush(stdout);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
len *= 2;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Barrier(MPI_COMM_WORLD);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Test Sendrecv, head to head */
|
|
Packit Service |
c5cf8c |
if (wrank == 0 && verbose) {
|
|
Packit Service |
c5cf8c |
printf("Sendrecv\n");
|
|
Packit Service |
c5cf8c |
printf("len\ttime (usec)\trate (MB/s)\n");
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Send powers of 2 bytes */
|
|
Packit Service |
c5cf8c |
len = 1;
|
|
Packit Service |
c5cf8c |
for (k = 0; k < 20; k++) {
|
|
Packit Service |
c5cf8c |
/* We use a simple linear form for the number of tests to
|
|
Packit Service |
c5cf8c |
* reduce the impact of the granularity of the timer */
|
|
Packit Service |
c5cf8c |
reps = 50 - k;
|
|
Packit Service |
c5cf8c |
repsleft = reps;
|
|
Packit Service |
c5cf8c |
/* Make sure that both processes are ready to start */
|
|
Packit Service |
c5cf8c |
MPI_Sendrecv(MPI_BOTTOM, 0, MPI_BYTE, partner, 0,
|
|
Packit Service |
c5cf8c |
MPI_BOTTOM, 0, MPI_BYTE, partner, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
|
|
Packit Service |
c5cf8c |
t1 = MPI_Wtime();
|
|
Packit Service |
c5cf8c |
while (repsleft--) {
|
|
Packit Service |
c5cf8c |
MPI_Sendrecv(sbuf, len, MPI_BYTE, partner, k,
|
|
Packit Service |
c5cf8c |
rbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
t1 = MPI_Wtime() - t1;
|
|
Packit Service |
c5cf8c |
times[1][k] = t1 / reps;
|
|
Packit Service |
c5cf8c |
if (wrank == 0) {
|
|
Packit Service |
c5cf8c |
t1 = t1 / reps;
|
|
Packit Service |
c5cf8c |
if (t1 > 0) {
|
|
Packit Service |
c5cf8c |
double rate;
|
|
Packit Service |
c5cf8c |
rate = (len / t1) / 1.e6;
|
|
Packit Service |
c5cf8c |
t1 = t1 * 1.e6;
|
|
Packit Service |
c5cf8c |
if (verbose)
|
|
Packit Service |
c5cf8c |
printf("%d\t%g\t%g\n", len, t1, len / t1);
|
|
Packit Service |
c5cf8c |
} else {
|
|
Packit Service |
c5cf8c |
t1 = t1 * 1.e6;
|
|
Packit Service |
c5cf8c |
if (verbose)
|
|
Packit Service |
c5cf8c |
printf("%d\t%g\tINF\n", len, t1);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
if (verbose)
|
|
Packit Service |
c5cf8c |
fflush(stdout);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
len *= 2;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPI_Barrier(MPI_COMM_WORLD);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Test Send/recv, ping-pong */
|
|
Packit Service |
c5cf8c |
if (wrank == 0 && verbose) {
|
|
Packit Service |
c5cf8c |
printf("Pingpong\n");
|
|
Packit Service |
c5cf8c |
printf("len\ttime (usec)\trate (MB/s)\n");
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Send powers of 2 bytes */
|
|
Packit Service |
c5cf8c |
len = 1;
|
|
Packit Service |
c5cf8c |
for (k = 0; k < 20; k++) {
|
|
Packit Service |
c5cf8c |
/* We use a simple linear form for the number of tests to
|
|
Packit Service |
c5cf8c |
* reduce the impact of the granularity of the timer */
|
|
Packit Service |
c5cf8c |
reps = 50 - k;
|
|
Packit Service |
c5cf8c |
repsleft = reps;
|
|
Packit Service |
c5cf8c |
/* Make sure that both processes are ready to start */
|
|
Packit Service |
c5cf8c |
MPI_Sendrecv(MPI_BOTTOM, 0, MPI_BYTE, partner, 0,
|
|
Packit Service |
c5cf8c |
MPI_BOTTOM, 0, MPI_BYTE, partner, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
|
|
Packit Service |
c5cf8c |
t1 = MPI_Wtime();
|
|
Packit Service |
c5cf8c |
while (repsleft--) {
|
|
Packit Service |
c5cf8c |
if (wrank & 0x1) {
|
|
Packit Service |
c5cf8c |
MPI_Send(sbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD);
|
|
Packit Service |
c5cf8c |
MPI_Recv(rbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
|
|
Packit Service |
c5cf8c |
} else {
|
|
Packit Service |
c5cf8c |
MPI_Recv(rbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
|
|
Packit Service |
c5cf8c |
MPI_Send(sbuf, len, MPI_BYTE, partner, k, MPI_COMM_WORLD);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
t1 = MPI_Wtime() - t1;
|
|
Packit Service |
c5cf8c |
times[2][k] = t1 / reps;
|
|
Packit Service |
c5cf8c |
if (wrank == 0) {
|
|
Packit Service |
c5cf8c |
t1 = t1 / reps;
|
|
Packit Service |
c5cf8c |
if (t1 > 0) {
|
|
Packit Service |
c5cf8c |
double rate;
|
|
Packit Service |
c5cf8c |
rate = (len / t1) / 1.e6;
|
|
Packit Service |
c5cf8c |
t1 = t1 * 1.e6;
|
|
Packit Service |
c5cf8c |
if (verbose)
|
|
Packit Service |
c5cf8c |
printf("%d\t%g\t%g\n", len, t1, len / t1);
|
|
Packit Service |
c5cf8c |
} else {
|
|
Packit Service |
c5cf8c |
t1 = t1 * 1.e6;
|
|
Packit Service |
c5cf8c |
if (verbose)
|
|
Packit Service |
c5cf8c |
printf("%d\t%g\tINF\n", len, t1);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
if (verbose)
|
|
Packit Service |
c5cf8c |
fflush(stdout);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
len *= 2;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* At this point, we could optionally analyze the results and report
|
|
Packit Service |
c5cf8c |
* success or failure based on some criteria, such as near monotone
|
|
Packit Service |
c5cf8c |
* increases in bandwidth. This test was created because of a
|
|
Packit Service |
c5cf8c |
* fall-off in performance noted in the ch3:sock device:channel */
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
int nPerfErrors = 0;
|
|
Packit Service |
c5cf8c |
if (wrank == 0) {
|
|
Packit Service |
c5cf8c |
len = 1;
|
|
Packit Service |
c5cf8c |
for (k = 0; k < 20; k++) {
|
|
Packit Service |
c5cf8c |
double T0, T1, T2;
|
|
Packit Service |
c5cf8c |
T0 = times[0][k] * 1.e6;
|
|
Packit Service |
c5cf8c |
T1 = times[1][k] * 1.e6;
|
|
Packit Service |
c5cf8c |
T2 = times[2][k] * 1.e6;
|
|
Packit Service |
c5cf8c |
if (verbose)
|
|
Packit Service |
c5cf8c |
printf("%d\t%12.2f\t%12.2f\t%12.2f\n", len, T0, T1, T2);
|
|
Packit Service |
c5cf8c |
/* Lets look at long messages only */
|
|
Packit Service |
c5cf8c |
if (k > 10) {
|
|
Packit Service |
c5cf8c |
double T0Old, T1Old, T2Old;
|
|
Packit Service |
c5cf8c |
T0Old = times[0][k - 1] * 1.0e6;
|
|
Packit Service |
c5cf8c |
T1Old = times[1][k - 1] * 1.0e6;
|
|
Packit Service |
c5cf8c |
T2Old = times[2][k - 1] * 1.0e6;
|
|
Packit Service |
c5cf8c |
if (T0 > (2 + ERROR_MARGIN) * T0Old) {
|
|
Packit Service |
c5cf8c |
nPerfErrors++;
|
|
Packit Service |
c5cf8c |
if (verbose)
|
|
Packit Service |
c5cf8c |
printf("Irecv-Send:\t%d\t%12.2f\t%12.2f\n", len, T0Old, T0);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
if (T1 > (2 + ERROR_MARGIN) * T1Old) {
|
|
Packit Service |
c5cf8c |
nPerfErrors++;
|
|
Packit Service |
c5cf8c |
if (verbose)
|
|
Packit Service |
c5cf8c |
printf("Sendrecv:\t%d\t%12.2f\t%12.2f\n", len, T1Old, T1);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
if (T2 > (2 + ERROR_MARGIN) * T2Old) {
|
|
Packit Service |
c5cf8c |
nPerfErrors++;
|
|
Packit Service |
c5cf8c |
if (verbose)
|
|
Packit Service |
c5cf8c |
printf("Pingpong:\t%d\t%12.2f\t%12.2f\n", len, T2Old, T2);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
len *= 2;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
fflush(stdout);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
free(sbuf);
|
|
Packit Service |
c5cf8c |
free(rbuf);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MTest_Finalize(nPerfErrors);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
return MTestReturnValue(nPerfErrors);
|
|
Packit Service |
c5cf8c |
}
|