mirror of
https://github.com/PhasicFlow/phasicFlow.git
synced 2025-07-08 03:07:03 +00:00
469 lines
14 KiB
C
469 lines
14 KiB
C
/*
|
|
* @HEADER
|
|
*
|
|
* ***********************************************************************
|
|
*
|
|
* Zoltan Toolkit for Load-balancing, Partitioning, Ordering and Coloring
|
|
* Copyright 2012 Sandia Corporation
|
|
*
|
|
* Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
|
|
* the U.S. Government retains certain rights in this software.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the Corporation nor the names of the
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* Questions? Contact Karen Devine kddevin@sandia.gov
|
|
* Erik Boman egboman@sandia.gov
|
|
*
|
|
* ***********************************************************************
|
|
*
|
|
* @HEADER
|
|
*/
|
|
|
|
|
|
#include "zoltan_timer.h"
|
|
#include "zoltan_types.h"
|
|
#include "zoltan_util.h"
|
|
#include "zoltan_mem.h"
|
|
|
|
#ifdef VAMPIR
|
|
#include <VT.h>
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
/* if C++, define the rest of this header file as extern C */
|
|
extern "C" {
|
|
#endif
|
|
|
|
/****************************************************************************/
|
|
/*
|
|
* Functions that implement a Timer "class," creating a Timer object
|
|
* with start, stop and print functions.
|
|
*
|
|
* This code was designed to be a stand-alone utility, relying only
|
|
* on Zoltan_Time, Zoltan error codes, Zoltan utilities, and libzoltan_mem.a.
|
|
* Some rearranging of the Zoltan_Time files is necessary to truly make
|
|
* this utility a standalone one.
|
|
*/
|
|
|
|
/****************************************************************************/
|
|
/* Number of timers initially in Timer object. */
|
|
#define INITLENGTH 30
|
|
|
|
/* Length of character strings naming each timer. */
|
|
/* If you change this constant, change the string format */
|
|
/* in Zoltan_Timer_Print, too. */
|
|
#define MAXNAMELEN 31
|
|
|
|
/* Flag indicating whether a timer is in use. */
|
|
#define INUSE 1
|
|
|
|
/* Flag indicating whether a timer is running. */
|
|
#define RUNNING 2
|
|
|
|
#define FATALERROR(yo, str) \
|
|
{ \
|
|
int ppproc; \
|
|
MPI_Comm_rank(MPI_COMM_WORLD, &ppproc); \
|
|
ZOLTAN_PRINT_ERROR(ppproc, yo, str); \
|
|
return ZOLTAN_FATAL; \
|
|
}
|
|
|
|
|
|
/* Macro to ensure that a Timer object is non-NULL */
|
|
#define TESTTIMER(zt, yo) \
|
|
if ((zt) == NULL) FATALERROR(yo, "NULL Zoltan_Timer")
|
|
|
|
/* Macro to ensure that a given timer index is valid. */
|
|
#define TESTINDEX(zt, ts_idx, yo) \
|
|
if ((ts_idx) >= (zt)->NextTimeStruct) FATALERROR(yo, "Invalid Timer Index")
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Structure that implements an individual timer. */
|
|
typedef struct TimeStruct {
|
|
double Start_Time; /* Most recent start time;
|
|
set by Zoltan_Timer_Start */
|
|
double Stop_Time; /* Most recent end time;
|
|
set by Zoltan_Timer_Stop */
|
|
char Start_File[MAXNAMELEN+1]; /* Filename for most recent Start */
|
|
char Stop_File[MAXNAMELEN+1]; /* Filename for most recent Stop */
|
|
int Start_Line; /* Line # in Start_File for most recent Start */
|
|
int Stop_Line; /* Line # in Stop_File for most recent Stop */
|
|
double My_Tot_Time; /* Sum of stop_time-start_time over all invocations
|
|
of this timer */
|
|
int Use_Barrier; /* Flag indicating whether to perform a barrier
|
|
operation before starting the timer. */
|
|
int Status; /* Flag indicating status of TimeStruct:
|
|
> 0 --> In Use
|
|
> 2 --> Running */
|
|
char Name[MAXNAMELEN+1];/* String associated (and printed) with timer info */
|
|
|
|
#ifdef VAMPIR
|
|
int vt_handle; /* state handle for vampir traces */
|
|
#endif
|
|
} ZTIMER_TS;
|
|
|
|
/* Timer object consisting of many related timers.
|
|
* Applications access this structure. */
|
|
typedef struct Zoltan_Timer {
|
|
int Timer_Flag; /* Zoltan Timer_Flag flag passed to Zoltan_Time */
|
|
int Length; /* # of entries allocated in Times */
|
|
int NextTimeStruct; /* Index of next unused TimeStruct */
|
|
ZTIMER_TS *Times; /* Array of actual timing data -- individual timers */
|
|
} ZTIMER;
|
|
/****************************************************************************/
|
|
|
|
ZTIMER *Zoltan_Timer_Copy(ZTIMER *from)
|
|
{
|
|
ZTIMER *to = NULL;
|
|
|
|
Zoltan_Timer_Copy_To(&to, from);
|
|
|
|
return to;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
int Zoltan_Timer_Copy_To(ZTIMER **to, ZTIMER *from)
|
|
{
|
|
ZTIMER *toptr = NULL;
|
|
if (!to){
|
|
return ZOLTAN_FATAL;
|
|
}
|
|
|
|
if (*to){
|
|
Zoltan_Timer_Destroy(to);
|
|
}
|
|
|
|
if (from){
|
|
*to = (ZTIMER *)ZOLTAN_MALLOC(sizeof(ZTIMER));
|
|
toptr = *to;
|
|
|
|
toptr->Timer_Flag = from->Timer_Flag;
|
|
toptr->Length = from->Length;
|
|
toptr->NextTimeStruct = from->NextTimeStruct;
|
|
if (toptr->Length > 0){
|
|
toptr->Times = (ZTIMER_TS *)ZOLTAN_MALLOC(sizeof(ZTIMER_TS) * toptr->Length);
|
|
memcpy(toptr->Times, from->Times, sizeof(ZTIMER_TS) * toptr->Length);
|
|
}
|
|
else{
|
|
toptr->Times = NULL;
|
|
}
|
|
}
|
|
|
|
return ZOLTAN_OK;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
ZTIMER *Zoltan_Timer_Create(
|
|
int timer_flag
|
|
)
|
|
{
|
|
/* Allocates a Timer object for the application; returns a pointer to it.
|
|
* Does not start any timers.
|
|
*/
|
|
|
|
ZTIMER *zt;
|
|
int i;
|
|
|
|
zt = (ZTIMER *) ZOLTAN_MALLOC(sizeof(ZTIMER));
|
|
zt->Times = (ZTIMER_TS *) ZOLTAN_MALLOC(sizeof(ZTIMER_TS) * INITLENGTH);
|
|
zt->Timer_Flag = timer_flag;
|
|
zt->Length = INITLENGTH;
|
|
zt->NextTimeStruct = 0;
|
|
|
|
for (i = 0; i < zt->Length; i++)
|
|
zt->Times[i].Status = 0;
|
|
|
|
return zt;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
int Zoltan_Timer_Init(
|
|
ZTIMER *zt, /* Ptr to Timer object */
|
|
int use_barrier, /* Flag indicating whether to perform a
|
|
barrier operation before starting the
|
|
timer. */
|
|
const char *name /* Name of this timer */
|
|
)
|
|
{
|
|
/* Function that returns the index of the next available Timer timer. */
|
|
int ret;
|
|
static char *yo = "Zoltan_Timer_Init";
|
|
|
|
TESTTIMER(zt, yo);
|
|
|
|
ret = zt->NextTimeStruct++;
|
|
|
|
if (ret >= zt->Length) {
|
|
/* Realloc -- need more individual timers */
|
|
zt->Length += INITLENGTH;
|
|
zt->Times = (ZTIMER_TS *) ZOLTAN_REALLOC(zt->Times, zt->Length * sizeof(ZTIMER_TS));
|
|
}
|
|
|
|
Zoltan_Timer_Reset(zt, ret, use_barrier, name);
|
|
|
|
#ifdef VAMPIR
|
|
if (VT_funcdef(name, VT_NOCLASS, &((zt->Times[ret]).vt_handle)) != VT_OK)
|
|
FATALERROR(yo, "VT_funcdef failed.");
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
int Zoltan_Timer_Reset(
|
|
ZTIMER *zt,
|
|
int ts_idx, /* Index of the timer to reset */
|
|
int use_barrier, /* Flag indicating whether to perform a
|
|
barrier operation before starting the
|
|
timer. */
|
|
const char *name /* Name of this timer */
|
|
)
|
|
{
|
|
/* Initialize a timer for INUSE; reset its values to zero. */
|
|
static char *yo = "Zoltan_Timer_Reset";
|
|
ZTIMER_TS *ts;
|
|
|
|
TESTTIMER(zt, yo);
|
|
TESTINDEX(zt, ts_idx, yo);
|
|
|
|
ts = &(zt->Times[ts_idx]);
|
|
|
|
ts->Status = INUSE;
|
|
ts->Start_Time = 0.;
|
|
ts->Stop_Time = 0.;
|
|
ts->My_Tot_Time = 0.;
|
|
ts->Use_Barrier = use_barrier;
|
|
strncpy(ts->Name, name, MAXNAMELEN);
|
|
ts->Name[MAXNAMELEN] = '\0';
|
|
ts->Start_File[0] = '\0';
|
|
ts->Start_Line = -1;
|
|
ts->Stop_File[0] = '\0';
|
|
ts->Stop_Line = -1;
|
|
|
|
return ZOLTAN_OK;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
int Zoltan_Timer_ChangeFlag(
|
|
ZTIMER *zt,
|
|
int timer
|
|
)
|
|
{
|
|
static char *yo = "Zoltan_Timer_ChangeFlag";
|
|
|
|
TESTTIMER(zt, yo);
|
|
zt->Timer_Flag = timer;
|
|
return ZOLTAN_OK;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
int Zoltan_Timer_Start(
|
|
ZTIMER *zt, /* Ptr to Timer object */
|
|
int ts_idx, /* Index of the timer to use */
|
|
MPI_Comm comm, /* Communicator to use for synchronization,
|
|
if requested */
|
|
char *filename, /* Filename of file calling the Start */
|
|
int lineno /* Line number where Start was called */
|
|
)
|
|
{
|
|
ZTIMER_TS *ts;
|
|
static char *yo = "Zoltan_Timer_Start";
|
|
|
|
TESTTIMER(zt, yo);
|
|
TESTINDEX(zt, ts_idx, yo);
|
|
|
|
ts = &(zt->Times[ts_idx]);
|
|
if (ts->Status > RUNNING) {
|
|
char msg[256];
|
|
sprintf(msg,
|
|
"Cannot start timer %d at %s:%d; timer already running from %s:%d.",
|
|
ts_idx, filename, lineno, ts->Start_File, ts->Start_Line);
|
|
FATALERROR(yo, msg)
|
|
}
|
|
|
|
ts->Status += RUNNING;
|
|
strncpy(ts->Start_File, filename, MAXNAMELEN);
|
|
ts->Start_Line = lineno;
|
|
if (ts->Use_Barrier)
|
|
MPI_Barrier(comm);
|
|
|
|
ts->Start_Time = Zoltan_Time(zt->Timer_Flag);
|
|
|
|
#ifdef VAMPIR
|
|
if (VT_begin(ts->vt_handle) != VT_OK)
|
|
FATALERROR(yo, "VT_begin failed.");
|
|
#endif
|
|
|
|
return ZOLTAN_OK;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
int Zoltan_Timer_Stop(
|
|
ZTIMER *zt, /* Ptr to Timer object */
|
|
int ts_idx, /* Index of the timer to use */
|
|
MPI_Comm comm, /* Communicator to use for synchronization,
|
|
if requested */
|
|
char *filename, /* Filename of file calling the Stop */
|
|
int lineno /* Line number where Stop was called */
|
|
)
|
|
{
|
|
/* Function to stop a timer and accrue its information */
|
|
ZTIMER_TS *ts;
|
|
static char *yo = "Zoltan_Timer_Stop";
|
|
double my_time;
|
|
|
|
TESTTIMER(zt, yo);
|
|
TESTINDEX(zt, ts_idx, yo);
|
|
|
|
ts = &(zt->Times[ts_idx]);
|
|
if (ts->Status < RUNNING) {
|
|
if (ts->Stop_Line == -1)
|
|
FATALERROR(yo, "Cannot stop timer; timer never started.")
|
|
else {
|
|
char msg[256];
|
|
sprintf(msg,
|
|
"Cannot stop timer %d at %s:%d; "
|
|
"timer already stopped from %s:%d.",
|
|
ts_idx, filename, lineno, ts->Stop_File, ts->Stop_Line);
|
|
FATALERROR(yo, msg)
|
|
}
|
|
}
|
|
|
|
#ifdef VAMPIR
|
|
if (VT_end(ts->vt_handle) != VT_OK)
|
|
FATALERROR(yo, "VT_end failed.");
|
|
#endif
|
|
|
|
if (ts->Use_Barrier)
|
|
MPI_Barrier(comm);
|
|
ts->Stop_Time = Zoltan_Time(zt->Timer_Flag);
|
|
ts->Status -= RUNNING;
|
|
ts->Stop_Line = lineno;
|
|
strncpy(ts->Stop_File, filename, MAXNAMELEN);
|
|
my_time = ts->Stop_Time - ts->Start_Time;
|
|
|
|
ts->My_Tot_Time += my_time;
|
|
|
|
return ZOLTAN_OK;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
int Zoltan_Timer_Print(
|
|
ZTIMER *zt,
|
|
int ts_idx,
|
|
int proc, /* Rank of the processor (in comm) that should print the data. */
|
|
MPI_Comm comm,
|
|
FILE *fp
|
|
)
|
|
{
|
|
/* Accrues a single timer's values across a communicator and prints
|
|
* its information. This function must be called by all processors
|
|
* within the communicator.
|
|
*/
|
|
static char *yo = "Zoltan_Timer_Print";
|
|
ZTIMER_TS *ts;
|
|
int my_proc, nproc;
|
|
int restart = 0;
|
|
double max_time;
|
|
double min_time;
|
|
double sum_time;
|
|
|
|
TESTTIMER(zt, yo);
|
|
TESTINDEX(zt, ts_idx, yo);
|
|
MPI_Comm_rank(comm, &my_proc);
|
|
MPI_Comm_size(comm, &nproc);
|
|
|
|
ts = &(zt->Times[ts_idx]);
|
|
if (ts->Status > RUNNING) {
|
|
/* Timer is running; stop it before printing the times.
|
|
* Don't want to include print times in timer.
|
|
*/
|
|
restart = 1;
|
|
ZOLTAN_TIMER_STOP(zt, ts_idx, comm);
|
|
}
|
|
|
|
MPI_Allreduce(&(ts->My_Tot_Time), &max_time, 1, MPI_DOUBLE, MPI_MAX, comm);
|
|
MPI_Allreduce(&(ts->My_Tot_Time), &min_time, 1, MPI_DOUBLE, MPI_MIN, comm);
|
|
MPI_Allreduce(&(ts->My_Tot_Time), &sum_time, 1, MPI_DOUBLE, MPI_SUM, comm);
|
|
|
|
if (proc == my_proc)
|
|
fprintf(fp,
|
|
"%3d ZOLTAN_TIMER %3d %23s: MyTime %7.4f "
|
|
"MaxTime %7.4f MinTime %7.4f AvgTime %7.4f\n",
|
|
proc, ts_idx, ts->Name, ts->My_Tot_Time,
|
|
max_time, min_time, sum_time/nproc);
|
|
|
|
if (restart) {
|
|
/* We stopped the timer for printing; restart it now. */
|
|
ZOLTAN_TIMER_START(zt, ts_idx, comm);
|
|
}
|
|
|
|
return ZOLTAN_OK;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
int Zoltan_Timer_PrintAll(
|
|
ZTIMER *zt,
|
|
int proc, /* Rank of the processor (in comm) that should print the data. */
|
|
MPI_Comm comm,
|
|
FILE *fp
|
|
)
|
|
{
|
|
/* Function to print all timer information */
|
|
static char *yo = "Zoltan_Timer_PrintAll";
|
|
int i, ierr = ZOLTAN_OK;
|
|
|
|
TESTTIMER(zt, yo);
|
|
for (i = 0; i < zt->NextTimeStruct; i++)
|
|
if ((ierr = Zoltan_Timer_Print(zt, i, proc, comm, fp)) != ZOLTAN_OK)
|
|
break;
|
|
|
|
return ierr;
|
|
}
|
|
|
|
/****************************************************************************/
|
|
void Zoltan_Timer_Destroy(
|
|
ZTIMER **zt
|
|
)
|
|
{
|
|
/* Destroy a Timer object */
|
|
if (*zt != NULL) {
|
|
ZOLTAN_FREE(&((*zt)->Times));
|
|
ZOLTAN_FREE(zt);
|
|
}
|
|
}
|
|
|
|
/****************************************************************************/
|
|
#ifdef __cplusplus
|
|
} /* closing bracket for extern "C" */
|
|
#endif
|