Blame test/mpi/perf/sendrecvl.c

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
}