/* * @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 #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