/******************************************************************************
 * FILE: mpi_latency.c
 * DESCRIPTION:
 *   MPI Latency Timing Program - C Version
 *   In this example code, a MPI communication timing test is performed.
 *   MPI task 0 will send "reps" number of 1 byte messages to MPI task 1,
 *   waiting for a reply between each rep. Before and after timings are made
 *   for each rep and an average calculated when completed.
 * AUTHOR: Blaise Barney
 * LAST REVISED: 04/13/05
 ******************************************************************************/
#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>
#define NUMBER_REPS 1000

int main (int argc, char *argv[])
{
  int reps,                   /* number of samples per test */
  tag,                    /* MPI message tag parameter */
  numtasks,               /* number of MPI tasks */
  rank,                   /* my MPI task number */
  dest, source,           /* send/receive task designators */
  avgT,                   /* average time per rep in microseconds */
  rc,                     /* return code */
  n;
  double T1, T2,              /* start/end times per rep */
  sumT,                   /* sum of all reps times */
  deltaT;                 /* time for one rep */
  char msg;                   /* buffer containing 1 byte message */
  MPI_Status status;          /* MPI receive routine parameter */

  MPI_Init(&argc,&argv);
  MPI_Comm_size(MPI_COMM_WORLD,&numtasks);
  MPI_Comm_rank(MPI_COMM_WORLD,&rank);
  if (rank == 0 && numtasks != 2) {
    printf("Number of tasks = %d\n",numtasks);
    printf("Only need 2 tasks - extra will be ignored...\n");
  }
  MPI_Barrier(MPI_COMM_WORLD);

  sumT = 0;
  msg = 'x';
  tag = 1;
  reps = NUMBER_REPS;

  if (rank == 0) {
    /* round-trip latency timing test */
    printf("task %d has started...\n", rank);
    printf("Beginning latency timing test. Number of reps = %d.\n", reps);
    printf("***************************************************\n");
    printf("Rep#       T1               T2            deltaT\n");
    dest = 1;
    source = 1;
    for (n = 1; n <= reps; n++) {
      T1 = MPI_Wtime();     /* start time */
      /* send message to worker - message tag set to 1.  */
      /* If return code indicates error quit */
      rc = MPI_Send(&msg, 1, MPI_BYTE, dest, tag, MPI_COMM_WORLD);
      if (rc != MPI_SUCCESS) {
        printf("Send error in task 0!\n");
        MPI_Abort(MPI_COMM_WORLD, rc);
        exit(1);
      }
      /* Now wait to receive the echo reply from the worker  */
      /* If return code indicates error quit */
      rc = MPI_Recv(&msg, 1, MPI_BYTE, source, tag, MPI_COMM_WORLD,
          &status);
      if (rc != MPI_SUCCESS) {
        printf("Receive error in task 0!\n");
        MPI_Abort(MPI_COMM_WORLD, rc);
        exit(1);
      }
      T2 = MPI_Wtime();     /* end time */

      /* calculate round trip time and print */
      deltaT = T2 - T1;
      printf("%4d  %8.8f  %8.8f  %2.8f\n", n, T1, T2, deltaT);
      sumT += deltaT;
    }
    avgT = (sumT*1000000)/reps;
    printf("***************************************************\n");
    printf("\n*** Avg round trip time = %d microseconds\n", avgT);
    printf("*** Avg one way latency = %d microseconds\n", avgT/2);
  }

  else if (rank == 1) {
    printf("task %d has started...\n", rank);
    dest = 0;
    source = 0;
    for (n = 1; n <= reps; n++) {
      rc = MPI_Recv(&msg, 1, MPI_BYTE, source, tag, MPI_COMM_WORLD,
          &status);
      if (rc != MPI_SUCCESS) {
        printf("Receive error in task 1!\n");
        MPI_Abort(MPI_COMM_WORLD, rc);
        exit(1);
      }
      rc = MPI_Send(&msg, 1, MPI_BYTE, dest, tag, MPI_COMM_WORLD);
      if (rc != MPI_SUCCESS) {
        printf("Send error in task 1!\n");
        MPI_Abort(MPI_COMM_WORLD, rc);
        exit(1);
      }
    }
  }

  MPI_Finalize();
  exit(0);
}
