/****************************************************************************
**  SCALASCA    http://www.scalasca.org/                                   **
*****************************************************************************
**  Copyright (c) 1998-2012                                                **
**  Forschungszentrum Juelich GmbH, Juelich Supercomputing Centre          **
**                                                                         **
**  Copyright (c) 2010-2012                                                **
**  German Research School for Simulation Sciences GmbH,                   **
**  Laboratory for Parallel Programming                                    **
**                                                                         **
**  Copyright (c) 2003-2008                                                **
**  University of Tennessee, Innovative Computing Laboratory               **
**                                                                         **
**  See the file COPYRIGHT in the package base directory for details       **
****************************************************************************/

/**
 * @file  epk_mpiwrap_coll.c
 *
 * @brief C interface wrappers for collective communication
 */

#include <mpi.h>

#include "esd_event.h"

#include "epk_defs_mpi.h"
#include "epk_mpicom.h"
#include "epk_mpiwrap.h"

/**
 * @name C wrappers
 * @{
 */

#if defined(HAS_MPI_ALLGATHER) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Allgather
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 1.0
 * @ingroup coll
 */
int MPI_Allgather(void*        sendbuf,
                  int          sendcount,
                  MPI_Datatype sendtype,
                  void*        recvbuf,
                  int          recvcount,
                  MPI_Datatype recvtype,
                  MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     recvsz, sendsz, N;
    int     sendbytes = 0, recvbytes = 0;
    elg_ui4 root_loc  = ELG_NO_ID;

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_ALLGATHER]);

    return_val = PMPI_Allgather(sendbuf,
                                sendcount,
                                sendtype,
                                recvbuf,
                                recvcount,
                                recvtype,
                                comm);

    PMPI_Comm_size(comm, &N);
    PMPI_Type_size(recvtype, &recvsz);

    #if defined (HAS_MPI_IN_PLACE)
    if (sendbuf != MPI_IN_PLACE)
    #endif
    {
      PMPI_Type_size(sendtype, &sendsz);
      sendbytes = N * sendcount * sendsz;
      recvbytes = N * recvcount * recvsz;
    }
    #if defined (HAS_MPI_IN_PLACE)
    else
    {
      sendbytes = recvbytes = (N - 1) * recvcount * recvsz;
    }
    #endif

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_ALLGATHER],
                     root_loc, EPK_COMM_ID(comm),
                     sendbytes,
                     recvbytes);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Allgather(sendbuf,
                                sendcount,
                                sendtype,
                                recvbuf,
                                recvcount,
                                recvtype,
                                comm);
  }

  return return_val;
} /* MPI_Allgather */

#endif
#if defined(HAS_MPI_ALLGATHERV) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Allgatherv
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 1.0
 * @ingroup coll
 */
int MPI_Allgatherv(void*        sendbuf,
                   int          sendcount,
                   MPI_Datatype sendtype,
                   void*        recvbuf,
                   int*         recvcounts,
                   int*         displs,
                   MPI_Datatype recvtype,
                   MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     recvcount, recvsz, sendsz, i, N, me;
    int     sendbytes = 0;
    elg_ui4 root_loc  = ELG_NO_ID;

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_ALLGATHERV]);

    return_val = PMPI_Allgatherv(sendbuf,
                                 sendcount,
                                 sendtype,
                                 recvbuf,
                                 recvcounts,
                                 displs,
                                 recvtype,
                                 comm);

    PMPI_Comm_size(comm, &N);
    PMPI_Type_size(recvtype, &recvsz);
    PMPI_Comm_rank(comm, &me);

    #if defined (HAS_MPI_IN_PLACE)
    if (sendbuf != MPI_IN_PLACE)
    #endif
    {
      PMPI_Type_size(sendtype, &sendsz);
      sendbytes = N * sendcount * sendsz;
    }
    #if defined (HAS_MPI_IN_PLACE)
    else
    {
      sendbytes = (N - 1) * recvcounts[me] * recvsz;
    }
    #endif

    recvcount = 0;
    for (i = 0; i < N; i++)
    {
      recvcount += recvcounts[i];
    }

    #if defined (HAS_MPI_IN_PLACE)
    if (sendbuf == MPI_IN_PLACE)
    {
      recvcount -= recvcounts[me];
    }
    #endif

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_ALLGATHERV],
                     root_loc, EPK_COMM_ID(comm),
                     sendbytes,
                     recvcount * recvsz);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Allgatherv(sendbuf,
                                 sendcount,
                                 sendtype,
                                 recvbuf,
                                 recvcounts,
                                 displs,
                                 recvtype,
                                 comm);
  }

  return return_val;
} /* MPI_Allgatherv */

#endif
#if defined(HAS_MPI_ALLREDUCE) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Allreduce
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 1.0
 * @ingroup coll
 */
int MPI_Allreduce(void*        sendbuf,
                  void*        recvbuf,
                  int          count,
                  MPI_Datatype datatype,
                  MPI_Op       op,
                  MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     sz, N;
    int     sendbytes = 0, recvbytes = 0;
    elg_ui4 root_loc  = ELG_NO_ID;

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_ALLREDUCE]);

    return_val = PMPI_Allreduce(sendbuf,
                                recvbuf,
                                count,
                                datatype,
                                op,
                                comm);

    PMPI_Type_size(datatype, &sz);
    PMPI_Comm_size(comm, &N);

    #if defined (HAS_MPI_IN_PLACE)
    if (sendbuf == MPI_IN_PLACE)
    {
      sendbytes = recvbytes = (N - 1) * count * sz;
    }
    else
    #endif
    {
      sendbytes = recvbytes = N * count * sz;
    }

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_ALLREDUCE],
                     root_loc, EPK_COMM_ID(comm),
                     sendbytes,
                     recvbytes);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Allreduce(sendbuf,
                                recvbuf,
                                count,
                                datatype,
                                op,
                                comm);
  }

  return return_val;
} /* MPI_Allreduce */

#endif
#if defined(HAS_MPI_ALLTOALL) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Alltoall
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 1.0
 * @ingroup coll
 */
int MPI_Alltoall(void*        sendbuf,
                 int          sendcount,
                 MPI_Datatype sendtype,
                 void*        recvbuf,
                 int          recvcount,
                 MPI_Datatype recvtype,
                 MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     recvsz, N;
    elg_ui4 root_loc = ELG_NO_ID;
    int     bytes    = 0;

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_ALLTOALL]);

    return_val = PMPI_Alltoall(sendbuf,
                               sendcount,
                               sendtype,
                               recvbuf,
                               recvcount,
                               recvtype,
                               comm);

    PMPI_Type_size(recvtype, &recvsz);
    PMPI_Comm_size(comm, &N);

    #if defined (HAS_MPI_IN_PLACE)
    if (sendbuf == MPI_IN_PLACE)
    {
      --N;
    }
    #endif

    bytes = N * recvcount * recvsz;

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_ALLTOALL],
                     root_loc, EPK_COMM_ID(comm),
                     bytes,
                     bytes);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Alltoall(sendbuf,
                               sendcount,
                               sendtype,
                               recvbuf,
                               recvcount,
                               recvtype,
                               comm);
  }

  return return_val;
} /* MPI_Alltoall */

#endif
#if defined(HAS_MPI_ALLTOALLV) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Alltoallv
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 1.0
 * @ingroup coll
 */
int MPI_Alltoallv(void*        sendbuf,
                  int*         sendcounts,
                  int*         sdispls,
                  MPI_Datatype sendtype,
                  void*        recvbuf,
                  int*         recvcounts,
                  int*         rdispls,
                  MPI_Datatype recvtype,
                  MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     recvcount = 0, recvsz, sendsz, N, i, me;
    int     sendbytes = 0, recvbytes = 0;
    elg_ui4 root_loc  = ELG_NO_ID;

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_ALLTOALLV]);

    return_val = PMPI_Alltoallv(sendbuf,
                                sendcounts,
                                sdispls,
                                sendtype,
                                recvbuf,
                                recvcounts,
                                rdispls,
                                recvtype,
                                comm);

    PMPI_Comm_size(comm, &N);
    PMPI_Type_size(recvtype, &recvsz);

    #if defined (HAS_MPI_IN_PLACE)
    if (sendbuf != MPI_IN_PLACE)
    #endif
    {
      PMPI_Type_size(sendtype, &sendsz);
      for (i = 0; i < N; i++)
      {
        recvbytes += recvcounts[i] * recvsz;
        sendbytes += sendcounts[i] * sendsz;
      }
    }
    #if defined (HAS_MPI_IN_PLACE)
    else
    {
      PMPI_Comm_rank(comm, &me);
      for (i = 0; i < N; i++)
      {
        recvcount += recvcounts[i];
      }

      recvcount -= recvcounts[me];

      sendbytes = recvbytes = recvcount * recvsz;
    }
    #endif

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_ALLTOALLV],
                     root_loc, EPK_COMM_ID(comm),
                     sendbytes,
                     recvbytes);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Alltoallv(sendbuf,
                                sendcounts,
                                sdispls,
                                sendtype,
                                recvbuf,
                                recvcounts,
                                rdispls,
                                recvtype,
                                comm);
  }

  return return_val;
} /* MPI_Alltoallv */

#endif
#if defined(HAS_MPI_ALLTOALLW) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Alltoallw
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 2.0
 * @ingroup coll
 */
int MPI_Alltoallw(void*        sendbuf,
                  int          sendcounts[],
                  int          sdispls[],
                  MPI_Datatype sendtypes[],
                  void*        recvbuf,
                  int          recvcounts[],
                  int          rdispls[],
                  MPI_Datatype recvtypes[],
                  MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     recvsz, sendsz, N, i, me;
    int     sendbytes = 0, recvbytes = 0;
    elg_ui4 root_loc  = ELG_NO_ID;

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_ALLTOALLW]);

    return_val = PMPI_Alltoallw(sendbuf,
                                sendcounts,
                                sdispls,
                                sendtypes,
                                recvbuf,
                                recvcounts,
                                rdispls,
                                recvtypes,
                                comm);

    PMPI_Comm_size(comm, &N);

    #if defined (HAS_MPI_IN_PLACE)
    if (sendbuf != MPI_IN_PLACE)
    #endif
    {
      for (i = 0; i < N; i++)
      {
        PMPI_Type_size(recvtypes[i], &recvsz);
        recvbytes += recvcounts[i] * recvsz;

        PMPI_Type_size(sendtypes[i], &sendsz);
        sendbytes += sendcounts[i] * sendsz;
      }
    }
    #if defined (HAS_MPI_IN_PLACE)
    else
    {
      PMPI_Comm_rank(comm, &me);

      for (i = 0; i < N; i++)
      {
        PMPI_Type_size(recvtypes[i], &recvsz);
        recvbytes += recvcounts[i] * recvsz;
      }

      PMPI_Type_size(recvtypes[me], &recvsz);
      recvbytes -= recvcounts[me] * recvsz;

      sendbytes = recvbytes;
    }
    #endif

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_ALLTOALLW],
                     root_loc, EPK_COMM_ID(comm),
                     sendbytes,
                     recvbytes);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Alltoallw(sendbuf,
                                sendcounts,
                                sdispls,
                                sendtypes,
                                recvbuf,
                                recvcounts,
                                rdispls,
                                recvtypes,
                                comm);
  }

  return return_val;
} /* MPI_Alltoallw */

#endif
#if defined(HAS_MPI_BARRIER) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Barrier
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 1.0
 * @ingroup coll
 */
int MPI_Barrier(MPI_Comm comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    elg_ui4 root_loc = ELG_NO_ID;

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_BARRIER]);

    return_val = PMPI_Barrier(comm);

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_BARRIER],
                     root_loc, EPK_COMM_ID(comm),
                     0,
                     0);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Barrier(comm);
  }

  return return_val;
}

#endif
#if defined(HAS_MPI_BCAST) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Bcast
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 1.0
 * @ingroup coll
 */
int MPI_Bcast(void*        buffer,
              int          count,
              MPI_Datatype datatype,
              int          root,
              MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     sz, N, me;
    elg_ui4 root_loc = EPK_RANK(root);

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_BCAST]);

    return_val = PMPI_Bcast(buffer, count, datatype, root, comm);

    PMPI_Type_size(datatype, &sz);
    PMPI_Comm_rank(comm, &me);
    if (me == root)
    {
      PMPI_Comm_size(comm, &N);
    }
    else
    {
      N = 0;
    }

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_BCAST],
                     root_loc, EPK_COMM_ID(comm),
                     N * count * sz,
                     count * sz);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Bcast(buffer, count, datatype, root, comm);
  }

  return return_val;
} /* MPI_Bcast */

#endif
#if defined(HAS_MPI_EXSCAN) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Exscan
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 2.0
 * @ingroup coll
 */
int MPI_Exscan(void*        sendbuf,
               void*        recvbuf,
               int          count,
               MPI_Datatype datatype,
               MPI_Op       op,
               MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     sz, me, N;
    elg_ui4 root_loc = ELG_NO_ID;

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_EXSCAN]);

    return_val = PMPI_Exscan(sendbuf, recvbuf, count, datatype, op, comm);

    PMPI_Type_size(datatype, &sz);
    PMPI_Comm_rank(comm, &me);
    PMPI_Comm_size(comm, &N);

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_EXSCAN],
                     root_loc, EPK_COMM_ID(comm),
                     (N - me - 1) * sz * count,
                     me * sz * count);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Exscan(sendbuf, recvbuf, count, datatype, op, comm);
  }

  return return_val;
} /* MPI_Exscan */

#endif
#if defined(HAS_MPI_GATHER) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Gather
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 1.0
 * @ingroup coll
 */
int MPI_Gather(void*        sendbuf,
               int          sendcount,
               MPI_Datatype sendtype,
               void*        recvbuf,
               int          recvcount,
               MPI_Datatype recvtype,
               int          root,
               MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     sendsz, recvsz, N, me;
    int     sendbytes = 0, recvbytes = 0;
    elg_ui4 root_loc  = EPK_RANK(root);

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_GATHER]);

    return_val = PMPI_Gather(sendbuf,
                             sendcount,
                             sendtype,
                             recvbuf,
                             recvcount,
                             recvtype,
                             root,
                             comm);

    #if defined (HAS_MPI_IN_PLACE)
    if (sendbuf != MPI_IN_PLACE)
    #endif
    {
      PMPI_Type_size(sendtype, &sendsz);
      sendbytes = sendcount * sendsz;
    }
    /* MPI_IN_PLACE: sendbytes is initialized to 0 */

    PMPI_Comm_rank(comm, &me);
    if (me == root)
    {
      PMPI_Comm_size(comm, &N);
      PMPI_Type_size(recvtype, &recvsz);
      #if defined (HAS_MPI_IN_PLACE)
      if (sendbuf == MPI_IN_PLACE)
      {
        --N;
      }
      #endif
      recvbytes = recvcount * N * recvsz;
    }

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_GATHER],
                     root_loc, EPK_COMM_ID(comm),
                     sendbytes,
                     recvbytes);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Gather(sendbuf,
                             sendcount,
                             sendtype,
                             recvbuf,
                             recvcount,
                             recvtype,
                             root,
                             comm);
  }

  return return_val;
} /* MPI_Gather */

#endif
#if defined(HAS_MPI_GATHERV) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Gatherv
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 1.0
 * @ingroup coll
 */
int MPI_Gatherv(void*        sendbuf,
                int          sendcount,
                MPI_Datatype sendtype,
                void*        recvbuf,
                int*         recvcounts,
                int*         displs,
                MPI_Datatype recvtype,
                int          root,
                MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     recvsz, sendsz, me, N, i;
    int     sendbytes = 0, recvbytes = 0;
    elg_ui4 root_loc  = EPK_RANK(root);

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_GATHERV]);

    return_val = PMPI_Gatherv(sendbuf,
                              sendcount,
                              sendtype,
                              recvbuf,
                              recvcounts,
                              displs,
                              recvtype,
                              root,
                              comm);

    #if defined (HAS_MPI_IN_PLACE)
    if (sendbuf != MPI_IN_PLACE)
    #endif
    {
      PMPI_Type_size(sendtype, &sendsz);
      sendbytes = sendcount * sendsz;
    }
    /* MPI_IN_PLACE: sendbytes is initialized to 0 */

    PMPI_Comm_rank(comm, &me);
    if (me == root)
    {
      PMPI_Comm_size(comm, &N);
      PMPI_Type_size(recvtype, &recvsz);

      for (i = 0; i < N; ++i)
      {
        recvbytes += recvcounts[i] * recvsz;
      }

      #if defined (HAS_MPI_IN_PLACE)
      if (sendbuf == MPI_IN_PLACE)
      {
        recvbytes -= recvcounts[me] * recvsz;
      }
      #endif
    }

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_GATHERV],
                     root_loc, EPK_COMM_ID(comm),
                     sendbytes,
                     recvbytes);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Gatherv(sendbuf,
                              sendcount,
                              sendtype,
                              recvbuf,
                              recvcounts,
                              displs,
                              recvtype,
                              root,
                              comm);
  }

  return return_val;
} /* MPI_Gatherv */

#endif
#if defined(HAS_MPI_REDUCE) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Reduce
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 1.0
 * @ingroup coll
 */
int MPI_Reduce(void*        sendbuf,
               void*        recvbuf,
               int          count,
               MPI_Datatype datatype,
               MPI_Op       op,
               int          root,
               MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     sz, me, N;
    int     sendbytes = 0, recvbytes = 0;
    elg_ui4 root_loc  = EPK_RANK(root);

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_REDUCE]);

    return_val = PMPI_Reduce(sendbuf,
                             recvbuf,
                             count,
                             datatype,
                             op,
                             root,
                             comm);

    PMPI_Type_size(datatype, &sz);
    PMPI_Comm_rank(comm, &me);
    PMPI_Comm_size(comm, &N);

    #if defined (HAS_MPI_IN_PLACE)
    if (sendbuf != MPI_IN_PLACE)
    #endif
    {
      sendbytes = count * sz;
    }
    #if defined (HAS_MPI_IN_PLACE)
    else
    #endif
    {
      --N;
    }

    if (root == me)
    {
      recvbytes = N * count * sz;
    }

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_REDUCE],
                     root_loc, EPK_COMM_ID(comm),
                     sendbytes,
                     recvbytes);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Reduce(sendbuf,
                             recvbuf,
                             count,
                             datatype,
                             op,
                             root,
                             comm);
  }

  return return_val;
} /* MPI_Reduce */

#endif
#if defined(HAS_MPI_REDUCE_SCATTER) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Reduce_scatter
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 1.0
 * @ingroup coll
 */
int MPI_Reduce_scatter(void*        sendbuf,
                       void*        recvbuf,
                       int*         recvcounts,
                       MPI_Datatype datatype,
                       MPI_Op       op,
                       MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     i, sz, me, N, count = 0;
    int     sendbytes = 0, recvbytes = 0;
    elg_ui4 root_loc  = ELG_NO_ID;

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_REDUCE_SCATTER]);

    return_val = PMPI_Reduce_scatter(sendbuf,
                                     recvbuf,
                                     recvcounts,
                                     datatype,
                                     op,
                                     comm);

    PMPI_Type_size(datatype, &sz);
    PMPI_Comm_rank(comm, &me);
    PMPI_Comm_size(comm, &N);
    for (i = 0; i < N; i++)
    {
      count += recvcounts[i];
    }
    #if defined (HAS_MPI_IN_PLACE)
    if (sendbuf == MPI_IN_PLACE)
    {
      sendbytes = (count - 1) * sz;
      recvbytes = (N - 1) * recvcounts[me] * sz;
    }
    else
    #endif
    {
      sendbytes = count * sz;
      recvbytes = N * recvcounts[me] * sz;
    }

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_REDUCE_SCATTER],
                     root_loc, EPK_COMM_ID(comm),
                     sendbytes,
                     recvbytes);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Reduce_scatter(sendbuf,
                                     recvbuf,
                                     recvcounts,
                                     datatype,
                                     op,
                                     comm);
  }

  return return_val;
} /* MPI_Reduce_scatter */

#endif
#if defined(HAS_MPI_REDUCE_SCATTER_BLOCK) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Reduce_scatter_block
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 2.2
 * @ingroup coll
 */
int MPI_Reduce_scatter_block(void*        sendbuf,
                             void*        recvbuf,
                             int          recvcount,
                             MPI_Datatype datatype,
                             MPI_Op       op,
                             MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     sz, N;
    elg_ui4 root_loc = ELG_NO_ID;

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_REDUCE_SCATTER_BLOCK]);

    return_val = PMPI_Reduce_scatter_block(sendbuf,
                                           recvbuf,
                                           recvcount,
                                           datatype,
                                           op,
                                           comm);

    PMPI_Type_size(datatype, &sz);
    PMPI_Comm_size(comm, &N);

    #if defined (HAS_MPI_IN_PLACE)
    if (sendbuf == MPI_IN_PLACE)
    {
      --N;
    }
    #endif

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_REDUCE_SCATTER_BLOCK],
                     root_loc, EPK_COMM_ID(comm),
                     N * recvcount * sz,
                     N * recvcount * sz);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Reduce_scatter_block(sendbuf,
                                           recvbuf,
                                           recvcount,
                                           datatype,
                                           op,
                                           comm);
  }

  return return_val;
} /* MPI_Reduce_scatter_block */

#endif
#if defined(HAS_MPI_SCAN) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Scan
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 1.0
 * @ingroup coll
 */
int MPI_Scan(void*        sendbuf,
             void*        recvbuf,
             int          count,
             MPI_Datatype datatype,
             MPI_Op       op,
             MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     sz, me, N;
    int     sendbytes = 0, recvbytes = 0;
    elg_ui4 root_loc  = ELG_NO_ID;

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_SCAN]);

    return_val = PMPI_Scan(sendbuf, recvbuf, count, datatype, op, comm);

    PMPI_Type_size(datatype, &sz);
    PMPI_Comm_rank(comm, &me);
    PMPI_Comm_size(comm, &N);

    #if defined (HAS_MPI_IN_PLACE)
    if (sendbuf == MPI_IN_PLACE)
    {
      sendbytes = (N - me - 1) * count * sz;
      recvbytes = me * count * sz;
    }
    else
    #endif
    {
      sendbytes = (N - me) * count * sz;
      recvbytes = (me + 1) * count * sz;
    }

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_SCAN],
                     root_loc, EPK_COMM_ID(comm),
                     sendbytes,
                     recvbytes);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Scan(sendbuf, recvbuf, count, datatype, op, comm);
  }

  return return_val;
} /* MPI_Scan */

#endif
#if defined(HAS_MPI_SCATTER) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Scatter
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 1.0
 * @ingroup coll
 */
int MPI_Scatter(void*        sendbuf,
                int          sendcount,
                MPI_Datatype sendtype,
                void*        recvbuf,
                int          recvcount,
                MPI_Datatype recvtype,
                int          root,
                MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     sendsz, recvsz, N, me;
    int     sendbytes = 0, recvbytes = 0;
    elg_ui4 root_loc  = EPK_RANK(root);

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_SCATTER]);

    return_val = PMPI_Scatter(sendbuf,
                              sendcount,
                              sendtype,
                              recvbuf,
                              recvcount,
                              recvtype,
                              root,
                              comm);

    PMPI_Comm_rank(comm, &me);
    #if defined (HAS_MPI_IN_PLACE)
    if (recvbuf != MPI_IN_PLACE)
    #endif
    {
      if (me == root)
      {
        PMPI_Comm_size(comm, &N);
        PMPI_Type_size(sendtype, &sendsz);
        sendbytes = N * sendcount * sendsz;
      }

      PMPI_Type_size(recvtype, &recvsz);
      recvbytes = recvcount * recvsz;
    }
    #if defined (HAS_MPI_IN_PLACE)
    else
    {
      PMPI_Comm_size(comm, &N);
      PMPI_Type_size(sendtype, &sendsz);
      sendbytes = (N - 1) * sendcount * sendsz;
      /* recvbytes is initialized to 0 */
    }
    #endif

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_SCATTER],
                     root_loc, EPK_COMM_ID(comm),
                     sendbytes,
                     recvbytes);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Scatter(sendbuf,
                              sendcount,
                              sendtype,
                              recvbuf,
                              recvcount,
                              recvtype,
                              root,
                              comm);
  }

  return return_val;
} /* MPI_Scatter */

#endif
#if defined(HAS_MPI_SCATTERV) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Scatterv
 * @note Auto-generated by wrapgen from template: coll.w
 * @note C interface
 * @note Introduced with MPI 1.0
 * @ingroup coll
 */
int MPI_Scatterv(void*        sendbuf,
                 int*         sendcounts,
                 int*         displs,
                 MPI_Datatype sendtype,
                 void*        recvbuf,
                 int          recvcount,
                 MPI_Datatype recvtype,
                 int          root,
                 MPI_Comm     comm)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    int     sendcount, sendsz, recvsz, me, N, i;
    int     recvbytes = 0;
    elg_ui4 root_loc  = EPK_RANK(root);

    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_SCATTERV]);

    return_val = PMPI_Scatterv(sendbuf,
                               sendcounts,
                               displs,
                               sendtype,
                               recvbuf,
                               recvcount,
                               recvtype,
                               root,
                               comm);

    sendcount = sendsz = 0;
    #if defined (HAS_MPI_IN_PLACE)
    if (recvbuf != MPI_IN_PLACE)
    #endif
    {
      PMPI_Type_size(recvtype, &recvsz);
      recvbytes = recvcount * recvsz;
    }
    /* MPI_IN_PLACE: recvbytes is initialized to 0 */

    PMPI_Comm_rank(comm, &me);
    if (me == root)
    {
      PMPI_Comm_size(comm, &N);
      PMPI_Type_size(sendtype, &sendsz);
      for (i = 0; i < N; i++)
      {
        sendcount += sendcounts[i];
      }

      #if defined (HAS_MPI_IN_PLACE)
      if (recvbuf == MPI_IN_PLACE)
      {
        sendcount -= sendcounts[me];
      }
      #endif
    }

    esd_mpi_collexit(epk_mpi_regid[EPK__MPI_SCATTERV],
                     root_loc, EPK_COMM_ID(comm),
                     sendcount * sendsz,
                     recvbytes);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Scatterv(sendbuf,
                               sendcounts,
                               displs,
                               sendtype,
                               recvbuf,
                               recvcount,
                               recvtype,
                               root,
                               comm);
  }

  return return_val;
} /* MPI_Scatterv */

#endif

#if defined(HAS_MPI_REDUCE_LOCAL) && !defined(NO_MPI_COLL)
/**
 * Measurement wrapper for MPI_Reduce_local
 * @note Auto-generated by wrapgen from template: std.w
 * @note C interface
 * @note Introduced with MPI 2.2
 * @ingroup coll
 */
int MPI_Reduce_local(void*        inbuf,
                     void*        inoutbuf,
                     int          count,
                     MPI_Datatype datatype,
                     MPI_Op       op)
{
  int return_val;

  if (IS_EVENT_GEN_ON_FOR(COLL))
  {
    EVENT_GEN_OFF();
    esd_enter(epk_mpi_regid[EPK__MPI_REDUCE_LOCAL]);

    return_val = PMPI_Reduce_local(inbuf, inoutbuf, count, datatype, op);

    esd_exit(epk_mpi_regid[EPK__MPI_REDUCE_LOCAL]);
    EVENT_GEN_ON();
  }
  else
  {
    return_val = PMPI_Reduce_local(inbuf, inoutbuf, count, datatype, op);
  }

  return return_val;
}

#endif

/**
 * @}
 */
