Files
phasicFlow/thirdParty/Zoltan/src/Utilities/Timer/zoltan_timer.c

469 lines
14 KiB
C
Raw Normal View History

2025-05-15 21:58:43 +03:30
/*
* @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