From bb3b99dacc48a7a4aae3ee1e2f4d1d61ff1927b0 Mon Sep 17 00:00:00 2001 From: eschnett Date: Tue, 24 Apr 2012 19:19:02 +0000 Subject: Allow different timers on different processes Gather not just the timer values but also the timer names from all processes. This allows different processes to have different timers. git-svn-id: http://svn.cactuscode.org/arrangements/CactusUtils/TimerReport/trunk@45 d0051148-8e13-4bef-be1d-f6c572c85f9f --- src/Output.c | 295 +++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 194 insertions(+), 101 deletions(-) diff --git a/src/Output.c b/src/Output.c index 31972cd..03bd303 100644 --- a/src/Output.c +++ b/src/Output.c @@ -7,24 +7,27 @@ @enddesc @@*/ +#include +#include +#include +#include +#include + #include #include #include #include -#include "cctk.h" -#include "cctk_Arguments.h" -#include "cctk_Parameters.h" -#include "cctk_Schedule.h" - -#include "util_String.h" +#ifdef CCTK_MPI +# include +#endif /******************************************************************** ********************* Local Data Types *********************** ********************************************************************/ struct timer_stats { - CCTK_REAL * restrict secs_local; /* process-local values */ + char ** restrict names; /* timer names */ CCTK_REAL * restrict secs_avg; /* global average */ CCTK_REAL * restrict secs_min; /* global minimum */ CCTK_REAL * restrict secs_max; /* global maximum */ @@ -391,7 +394,7 @@ static void OutputAllTimersTogether (CCTK_ARGUMENTS) fprintf(file_tsv, "simulation time"); for (int i = 0; i < timers.ntimers; i++) { - const char * const name = CCTK_TimerName(i); + const char * const name = timers.names[i]; fprintf(file, "# Column %d %s\n", 3*i+3, name ? name : ""); char *const name_csv = QuoteForCSV(name ? name : ""); fprintf(file_csv, @@ -445,10 +448,13 @@ static void OutputAllTimersTogether (CCTK_ARGUMENTS) } /* if root processor */ - free (timers.secs_local); - free (timers.secs_avg ); - free (timers.secs_min ); - free (timers.secs_max ); + for (int n=0; nntimers = CCTK_NumTimers(); - assert (timers->ntimers >= 0); - - /* Check that the number of timers is consistent across processors */ - CCTK_INT imin, imax; - if (!integer_same_on_all_procs(cctkGH, timers->ntimers, &imin, &imax)) - { - CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, - "Number of timers is inconsistent across processes; cannot collect timer information. Number of timers on processor %d: %d; overall minimum: %d; overall maximum: %d", - CCTK_MyProc(cctkGH), timers->ntimers, (int)imin, (int)imax); - return 0; + /* Gather number of timers from each process */ + int const myproc = CCTK_MyProc(cctkGH); + int const nprocs = CCTK_nProcs(cctkGH); + + int my_ntimers = CCTK_NumTimers(); + int all_ntimers[nprocs]; +#ifdef CCTK_MPI + MPI_Gather(&my_ntimers, 1, MPI_INT, all_ntimers, 1, MPI_INT, 0, + MPI_COMM_WORLD); +#else + memcpy(all_ntimers, &my_ntimers, sizeof *all_ntimers); +#endif + int total_ntimers = 0; + if (myproc == 0) { + for (int p=0; psecs_local = malloc(timers->ntimers * sizeof *timers->secs_local); - assert (timers->ntimers==0 || timers->secs_local); - if (CCTK_MyProc(cctkGH) == 0) - { - timers->secs_avg = malloc(timers->ntimers * sizeof *timers->secs_avg ); - timers->secs_min = malloc(timers->ntimers * sizeof *timers->secs_min ); - timers->secs_max = malloc(timers->ntimers * sizeof *timers->secs_max ); - assert (timers->ntimers==0 || timers->secs_avg ); - assert (timers->ntimers==0 || timers->secs_min ); - assert (timers->ntimers==0 || timers->secs_max ); + + /* Determine local timer names and their values */ + char my_timernames[my_ntimers][TIMERNAME_LENGTH]; + for (int n=0; nntimers = 0; + timers->names = NULL; timers->secs_avg = NULL; timers->secs_min = NULL; timers->secs_max = NULL; + + return 1; } - cTimerData * const td = CCTK_TimerCreateData(); - for (int i = 0; i < timers->ntimers; i++) - { - CCTK_TimerI(i, td); - const cTimerVal * const tv = CCTK_GetClockValue(all_timers_clock, td); - if (tv) - { - timers->secs_local[i] = CCTK_TimerClockSeconds(tv); - } - else - { - CCTK_VWarn(1, __LINE__, __FILE__, CCTK_THORNSTRING, - "Clock \"%s\" not found for timer #%d \"%s\"", - all_timers_clock, i, CCTK_TimerName(i)); - timers->secs_local[i] = -1; + /* Construct global list of timers: sort, then unique */ + /* TODO: sort the processes' timers separately (and in parallel), + then merge them */ + int sort_index[total_ntimers]; + for (int i=0; i 0) { + unique_timers = 1; /* first timer is always unique */ + for (int i=1; intimers = unique_timers; + assert(timers->ntimers >= 0); + + timers->names = malloc(timers->ntimers * sizeof *timers->names ); + timers->secs_avg = malloc(timers->ntimers * sizeof *timers->secs_avg); + timers->secs_min = malloc(timers->ntimers * sizeof *timers->secs_min); + timers->secs_max = malloc(timers->ntimers * sizeof *timers->secs_max); + assert(timers->ntimers==0 || timers->names ); + assert(timers->ntimers==0 || timers->secs_avg); + assert(timers->ntimers==0 || timers->secs_min); + assert(timers->ntimers==0 || timers->secs_max); + + for (int n=0; nnames[n] = strdup(all_timernames[sort_index[n]]); } - const int ierr1 = CCTK_ReduceLocArrayToArray1D - (cctkGH, 0, reduce_avg, - timers->secs_local, timers->secs_avg, timers->ntimers, CCTK_VARIABLE_REAL); - const int ierr2 = CCTK_ReduceLocArrayToArray1D - (cctkGH, 0, reduce_min, - timers->secs_local, timers->secs_min, timers->ntimers, CCTK_VARIABLE_REAL); - const int ierr3 = CCTK_ReduceLocArrayToArray1D - (cctkGH, 0, reduce_max, - timers->secs_local, timers->secs_max, timers->ntimers, CCTK_VARIABLE_REAL); - if (ierr1 || ierr2 || ierr3) - { - CCTK_WARN (CCTK_WARN_ABORT, - "Error in calling reduction operators"); + + /* Reduce timer values */ + for (int n=0; nntimers; ++n) { + double count = 0.0; + double sum = 0.0; + double minval = HUGE_VAL; + double maxval = 0.0; + /* Reduce over all processes */ + for (int p=0; pnames[n], all_timernames[name_offset+i]) == 0) break; + } + if (i < all_ntimers[p]) { + /* Found the timer */ + double const value = all_timervalues[value_displacements[p]+i]; + count += 1; + sum += value; + minval = fmin(minval, value); + maxval = fmax(maxval, value); + } else { + /* Timer does not exist on this process -- ignore */ + } + } + if (count == 0) { + /* Special case to make result look nicer */ + timers->secs_avg[n] = -1; /* instead of nan */ + timers->secs_min[n] = -1; /* instead of infinity */ + timers->secs_max[n] = maxval; /* zero */ + } else { + timers->secs_avg[n] = sum / count; + timers->secs_min[n] = minval; + timers->secs_max[n] = maxval; + } } + return 1; } -- cgit v1.2.3