From e4493116e7a6fd21a11cc5a5d76e88e4c4e7354f Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Mon, 7 Aug 2023 23:07:59 -0700 Subject: [PATCH 01/36] always use clock_gettime --- src/sundials/sundials_profiler.c | 35 +++++++------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index 2761b9e3dc..b26a48e83f 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -17,7 +17,9 @@ #if SUNDIALS_MPI_ENABLED #include #include -#elif defined(SUNDIALS_HAVE_POSIX_TIMERS) +#endif + +#if defined(SUNDIALS_HAVE_POSIX_TIMERS) /* Minimum POSIX version needed for struct timespec and clock_monotonic */ #if !defined(_POSIX_C_SOURCE) || (_POSIX_C_SOURCE < 199309L) #define _POSIX_C_SOURCE 199309L @@ -26,7 +28,7 @@ #include #include #else -#error Either MPI_Wtime or clock_getttime is required but neither were found +#error POSIX clock_gettime is required for profiling #endif #include @@ -53,13 +55,8 @@ static int sunCompareTimes(const void* l, const void* r); struct _sunTimerStruct { -#if SUNDIALS_MPI_ENABLED - double tic; - double toc; -#else struct timespec* tic; struct timespec* toc; -#endif double average; double maximum; double elapsed; @@ -71,15 +68,10 @@ typedef struct _sunTimerStruct sunTimerStruct; static sunTimerStruct* sunTimerStructNew() { sunTimerStruct* ts = (sunTimerStruct*) malloc(sizeof(sunTimerStruct)); -#if SUNDIALS_MPI_ENABLED - ts->tic = 0.0; - ts->toc = 0.0; -#else ts->tic = (struct timespec *) malloc(sizeof(struct timespec)); ts->toc = (struct timespec *) malloc(sizeof(struct timespec)); ts->tic->tv_sec = 0; ts->tic->tv_nsec = 0; -#endif ts->elapsed = 0.0; ts->average = 0.0; ts->maximum = 0.0; @@ -92,34 +84,23 @@ static void sunTimerStructFree(void* TS) sunTimerStruct* ts = (sunTimerStruct*) TS; if (ts) { -#if !SUNDIALS_MPI_ENABLED if (ts->tic) free(ts->tic); if (ts->toc) free(ts->toc); -#endif free(ts); } } static void sunStartTiming(sunTimerStruct* entry) { -#if SUNDIALS_MPI_ENABLED - entry->tic = MPI_Wtime(); -#else clock_gettime(CLOCK_MONOTONIC, entry->tic); -#endif } static void sunStopTiming(sunTimerStruct* entry) { -#if SUNDIALS_MPI_ENABLED - entry->toc = MPI_Wtime(); - entry->elapsed += entry->toc - entry->tic; -#else clock_gettime(CLOCK_MONOTONIC, entry->toc); entry->elapsed += ((double) (entry->toc->tv_sec - entry->tic->tv_sec) + (double) (entry->toc->tv_nsec - entry->tic->tv_nsec) * 1e-9); -#endif /* Initialize to total value */ entry->average = entry->elapsed; entry->maximum = entry->elapsed; @@ -127,15 +108,10 @@ static void sunStopTiming(sunTimerStruct* entry) static void sunResetTiming(sunTimerStruct* entry) { -#if SUNDIALS_MPI_ENABLED - entry->tic = 0.0; - entry->toc = 0.0; -#else entry->tic->tv_sec = 0; entry->tic->tv_nsec = 0; entry->toc->tv_sec = 0; entry->toc->tv_nsec = 0; -#endif entry->elapsed = 0.0; entry->average = 0.0; entry->maximum = 0.0; @@ -363,12 +339,15 @@ int SUNProfiler_Print(SUNProfiler p, FILE* fp) if (rank == 0) { + struct timespec spec; /* Sort the timers in descending order */ if (SUNHashMap_Sort(p->map, &sorted, sunCompareTimes)) return(-1); + clock_getres(CLOCK_MONOTONIC, &spec); fprintf(fp, "\n================================================================================================================\n"); fprintf(fp, "SUNDIALS GIT VERSION: %s\n", SUNDIALS_GIT_VERSION); fprintf(fp, "SUNDIALS PROFILER: %s\n", p->title); + fprintf(fp, "Timer resolution: %ld nanoseconds\n", spec.tv_nsec); fprintf(fp, "%-40s\t %% time (inclusive) \t max/rank \t average/rank \t count \n", "Results:"); fprintf(fp, "================================================================================================================\n"); From dbbf8c130498bf40fe714bc6992e81ea2d70b9f4 Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Tue, 8 Aug 2023 15:49:24 -0700 Subject: [PATCH 02/36] enable profiling and logging in windows github actions --- .github/workflows/windows-latest-mingw.yml | 2 +- .github/workflows/windows-latest.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows-latest-mingw.yml b/.github/workflows/windows-latest-mingw.yml index ef1fad6ee2..4ea9269788 100644 --- a/.github/workflows/windows-latest-mingw.yml +++ b/.github/workflows/windows-latest-mingw.yml @@ -21,7 +21,7 @@ jobs: - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -G "MinGW Makefiles" -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} + run: cmake -G "MinGW Makefiles" -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DSUNDIALS_BUILD_WITH_PROFILING=ON -DSUNDIALS_LOGGING_LEVEL=2 - name: Build # Build your program with the given configuration diff --git a/.github/workflows/windows-latest.yml b/.github/workflows/windows-latest.yml index fee4f246d9..8103c6df1a 100644 --- a/.github/workflows/windows-latest.yml +++ b/.github/workflows/windows-latest.yml @@ -17,7 +17,7 @@ jobs: - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_STATIC_LIBS=OFF + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_STATIC_LIBS=OFF -DSUNDIALS_BUILD_WITH_PROFILING=ON -DSUNDIALS_LOGGING_LEVEL=2 - name: Build # Build your program with the given configuration From 7cd4a7c8f5758b57ca3158f2d4af159777f7e944 Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Tue, 8 Aug 2023 16:39:59 -0700 Subject: [PATCH 03/36] fix subtraction of times --- src/sundials/sundials_profiler.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index b26a48e83f..4394424219 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -97,11 +97,20 @@ static void sunStartTiming(sunTimerStruct* entry) static void sunStopTiming(sunTimerStruct* entry) { + long s_difference = 0; + long ns_difference = 0; + clock_gettime(CLOCK_MONOTONIC, entry->toc); - entry->elapsed += - ((double) (entry->toc->tv_sec - entry->tic->tv_sec) + - (double) (entry->toc->tv_nsec - entry->tic->tv_nsec) * 1e-9); - /* Initialize to total value */ + + s_difference = entry->toc->tv_sec - entry->tic->tv_sec; + ns_difference = entry->toc->tv_nsec - entry->tic->tv_nsec; + if (ns_difference < 0.0) + { + s_difference--; + ns_difference = 1000000000 + entry->toc->tv_nsec - entry->tic->tv_nsec; + } + + entry->elapsed += ((double) s_difference) + ((double) ns_difference) * 1e-9; entry->average = entry->elapsed; entry->maximum = entry->elapsed; } From b459ddfce99843496b874a919abdb332f904d26d Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Tue, 8 Aug 2023 16:40:27 -0700 Subject: [PATCH 04/36] add windows implementation of gettime --- src/sundials/sundials_profiler.c | 42 +++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index 4394424219..f260fd0fb3 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -27,8 +27,8 @@ #include #include #include -#else -#error POSIX clock_gettime is required for profiling +#elif !(defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)) +#error POSIX is needed for clock_getttime #endif #include @@ -36,6 +36,7 @@ #include #include +#include "sundials_utils.h" #include "sundials_hashmap.h" #include "sundials_debug.h" @@ -47,6 +48,7 @@ static int sunCollectTimers(SUNProfiler p); #endif static void sunPrintTimers(int idx, SUNHashMapKeyValue kv, FILE* fp, void* pvoid); static int sunCompareTimes(const void* l, const void* r); +static int sunclock_gettime_monotonic(struct timespec* tp); /* sunTimerStruct. @@ -92,7 +94,7 @@ static void sunTimerStructFree(void* TS) static void sunStartTiming(sunTimerStruct* entry) { - clock_gettime(CLOCK_MONOTONIC, entry->tic); + sunclock_gettime_monotonic(entry->tic); } static void sunStopTiming(sunTimerStruct* entry) @@ -100,7 +102,7 @@ static void sunStopTiming(sunTimerStruct* entry) long s_difference = 0; long ns_difference = 0; - clock_gettime(CLOCK_MONOTONIC, entry->toc); + sunclock_gettime_monotonic(entry->toc); s_difference = entry->toc->tv_sec - entry->tic->tv_sec; ns_difference = entry->toc->tv_nsec - entry->tic->tv_nsec; @@ -356,8 +358,8 @@ int SUNProfiler_Print(SUNProfiler p, FILE* fp) fprintf(fp, "\n================================================================================================================\n"); fprintf(fp, "SUNDIALS GIT VERSION: %s\n", SUNDIALS_GIT_VERSION); fprintf(fp, "SUNDIALS PROFILER: %s\n", p->title); - fprintf(fp, "Timer resolution: %ld nanoseconds\n", spec.tv_nsec); - fprintf(fp, "%-40s\t %% time (inclusive) \t max/rank \t average/rank \t count \n", "Results:"); + fprintf(fp, "TIMER RESOLUTION: %gs\n", 1e-9 * ((double) spec.tv_nsec)); + fprintf(fp, "%-40s\t %% time (inclusive) \t max/rank \t average/rank \t count \n", "RESULTS:"); fprintf(fp, "================================================================================================================\n"); #if SUNDIALS_MPI_ENABLED @@ -503,3 +505,31 @@ int sunCompareTimes(const void* l, const void* r) return(-1); return(0); } + +int sunclock_gettime_monotonic(struct timespec* ts) +{ +#if (defined(WIN32) || defined(_WIN32)) + static LARGE_INTEGER ticks_per_sec; + LARGE_INTEGER ticks; + + if (!ticks_per_sec.QuadPart) + { + QueryPerformanceFrequency(&ticks_per_sec); + if (!ticks_per_sec.QuadPart) + { + errno = ENOTSUP; + return -1; + } + } + + QueryPerformanceCounter(&ticks); + + ts->ts_sec = (long)(ticks.QuadPart / ticks_per_sec.QuadPart); + ts->ts_nsec = (long)(((ticks.QuadPart % ticks_per_sec.QuadPart) * 1000000000) / + ticks_per_sec.QuadPart); + + return 0; +#else + return clock_gettime(CLOCK_MONOTONIC, ts); +#endif +} From b51603f5c5ad723a91f1e9646c6f9317589ef5d4 Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Tue, 8 Aug 2023 16:41:11 -0700 Subject: [PATCH 05/36] remove cygwin part --- src/sundials/sundials_profiler.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index f260fd0fb3..8fe9f8fb2d 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -27,7 +27,7 @@ #include #include #include -#elif !(defined(WIN32) || defined(_WIN32) || defined(__WIN32) && !defined(__CYGWIN__)) +#elif !(defined(WIN32) || defined(_WIN32)) #error POSIX is needed for clock_getttime #endif From 6964531400fd73409afcb6d4ac448126ee0fbd9f Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Fri, 11 Aug 2023 10:40:57 -0700 Subject: [PATCH 06/36] fix datatype for ticks --- src/sundials/sundials_profiler.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index 8fe9f8fb2d..7cab1910fb 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -509,8 +509,8 @@ int sunCompareTimes(const void* l, const void* r) int sunclock_gettime_monotonic(struct timespec* ts) { #if (defined(WIN32) || defined(_WIN32)) - static LARGE_INTEGER ticks_per_sec; - LARGE_INTEGER ticks; + static long ticks_per_sec; + long ticks; if (!ticks_per_sec.QuadPart) { @@ -524,8 +524,8 @@ int sunclock_gettime_monotonic(struct timespec* ts) QueryPerformanceCounter(&ticks); - ts->ts_sec = (long)(ticks.QuadPart / ticks_per_sec.QuadPart); - ts->ts_nsec = (long)(((ticks.QuadPart % ticks_per_sec.QuadPart) * 1000000000) / + ts->tv_sec = (long)(ticks.QuadPart / ticks_per_sec.QuadPart); + ts->tv_nsec = (long)(((ticks.QuadPart % ticks_per_sec.QuadPart) * 1000000000) / ticks_per_sec.QuadPart); return 0; From 6a21559b3968d0f3b3eb5260c7ef966360595a8c Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Fri, 11 Aug 2023 10:48:49 -0700 Subject: [PATCH 07/36] remove error for no posix --- cmake/SundialsSetupCompilers.cmake | 14 +++++++------- src/sundials/sundials_profiler.c | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmake/SundialsSetupCompilers.cmake b/cmake/SundialsSetupCompilers.cmake index 3cd0c055a0..2c52b4b406 100644 --- a/cmake/SundialsSetupCompilers.cmake +++ b/cmake/SundialsSetupCompilers.cmake @@ -223,13 +223,13 @@ if(SUNDIALS_POSIX_TIMERS AND POSIX_TIMERS_NEED_POSIX_C_SOURCE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_POSIX_C_SOURCE=${SUNDIALS_POSIX_C_SOURCE}") endif() -# Check if profiling is being built with no timers. -if(SUNDIALS_BUILD_WITH_PROFILING AND - (NOT ENABLE_CALIPER) AND - (NOT ENABLE_MPI) AND - (NOT SUNDIALS_POSIX_TIMERS)) - message(SEND_ERROR "The SUNDIALS native profiler requires POSIX timers or MPI_Wtime, but neither were found.") -endif() +# # Check if profiling is being built with no timers. +# if(SUNDIALS_BUILD_WITH_PROFILING AND +# (NOT ENABLE_CALIPER) AND +# (NOT ENABLE_MPI) AND +# (NOT SUNDIALS_POSIX_TIMERS)) +# message(SEND_ERROR "The SUNDIALS native profiler requires POSIX timers or MPI_Wtime, but neither were found.") +# endif() # --------------------------------------------------------------- # Check for deprecated attribute with message diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index 7cab1910fb..62d52e3fcf 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -508,7 +508,7 @@ int sunCompareTimes(const void* l, const void* r) int sunclock_gettime_monotonic(struct timespec* ts) { -#if (defined(WIN32) || defined(_WIN32)) +#if (defined(WIN32) || defined(_WIN32)) && !defined(SUNDIALS_HAVE_POSIX_TIMERS) static long ticks_per_sec; long ticks; From cf468c39aadee2a26d1d402db9520e160a82afdf Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Fri, 11 Aug 2023 13:54:25 -0700 Subject: [PATCH 08/36] declare a timespec if there is not one --- src/sundials/sundials_profiler.c | 243 ++++++++++++++++--------------- 1 file changed, 128 insertions(+), 115 deletions(-) diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index 62d52e3fcf..e4c11a32d5 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -15,8 +15,8 @@ #include #if SUNDIALS_MPI_ENABLED -#include #include +#include #endif #if defined(SUNDIALS_HAVE_POSIX_TIMERS) @@ -24,8 +24,8 @@ #if !defined(_POSIX_C_SOURCE) || (_POSIX_C_SOURCE < 199309L) #define _POSIX_C_SOURCE 199309L #endif -#include #include +#include #include #elif !(defined(WIN32) || defined(_WIN32)) #error POSIX is needed for clock_getttime @@ -33,14 +33,24 @@ #include #include - -#include #include -#include "sundials_utils.h" -#include "sundials_hashmap.h" +#include + #include "sundials_debug.h" +#include "sundials_hashmap.h" +#include "sundials_utils.h" -#define SUNDIALS_ROOT_TIMER ((const char*) "From profiler epoch") +#define SUNDIALS_ROOT_TIMER ((const char*)"From profiler epoch") + +#if (defined(WIN32) || defined(_WIN32)) && !defined(SUNDIALS_HAVE_POSIX_TIMERS) +typedef struct _sunTimespec +{ + long int tv_sec; + long int tv_nsec; +} sunTimespec; +#else +typedef struct timespec sunTimespec; +#endif /* Private functions */ #if SUNDIALS_MPI_ENABLED @@ -48,7 +58,7 @@ static int sunCollectTimers(SUNProfiler p); #endif static void sunPrintTimers(int idx, SUNHashMapKeyValue kv, FILE* fp, void* pvoid); static int sunCompareTimes(const void* l, const void* r); -static int sunclock_gettime_monotonic(struct timespec* tp); +static int sunclock_gettime_monotonic(sunTimespec* tp); /* sunTimerStruct. @@ -57,33 +67,33 @@ static int sunclock_gettime_monotonic(struct timespec* tp); struct _sunTimerStruct { - struct timespec* tic; - struct timespec* toc; + sunTimespec* tic; + sunTimespec* toc; double average; double maximum; double elapsed; - long count; + long count; }; typedef struct _sunTimerStruct sunTimerStruct; static sunTimerStruct* sunTimerStructNew() { - sunTimerStruct* ts = (sunTimerStruct*) malloc(sizeof(sunTimerStruct)); - ts->tic = (struct timespec *) malloc(sizeof(struct timespec)); - ts->toc = (struct timespec *) malloc(sizeof(struct timespec)); - ts->tic->tv_sec = 0; - ts->tic->tv_nsec = 0; - ts->elapsed = 0.0; - ts->average = 0.0; - ts->maximum = 0.0; - ts->count = 0; + sunTimerStruct* ts = (sunTimerStruct*)malloc(sizeof(sunTimerStruct)); + ts->tic = (sunTimespec*)malloc(sizeof(sunTimespec)); + ts->toc = (sunTimespec*)malloc(sizeof(sunTimespec)); + ts->tic->tv_sec = 0; + ts->tic->tv_nsec = 0; + ts->elapsed = 0.0; + ts->average = 0.0; + ts->maximum = 0.0; + ts->count = 0; return ts; } static void sunTimerStructFree(void* TS) { - sunTimerStruct* ts = (sunTimerStruct*) TS; + sunTimerStruct* ts = (sunTimerStruct*)TS; if (ts) { if (ts->tic) free(ts->tic); @@ -99,7 +109,7 @@ static void sunStartTiming(sunTimerStruct* entry) static void sunStopTiming(sunTimerStruct* entry) { - long s_difference = 0; + long s_difference = 0; long ns_difference = 0; sunclock_gettime_monotonic(entry->toc); @@ -112,7 +122,7 @@ static void sunStopTiming(sunTimerStruct* entry) ns_difference = 1000000000 + entry->toc->tv_nsec - entry->tic->tv_nsec; } - entry->elapsed += ((double) s_difference) + ((double) ns_difference) * 1e-9; + entry->elapsed += ((double)s_difference) + ((double)ns_difference) * 1e-9; entry->average = entry->elapsed; entry->maximum = entry->elapsed; } @@ -123,13 +133,12 @@ static void sunResetTiming(sunTimerStruct* entry) entry->tic->tv_nsec = 0; entry->toc->tv_sec = 0; entry->toc->tv_nsec = 0; - entry->elapsed = 0.0; - entry->average = 0.0; - entry->maximum = 0.0; - entry->count = 0; + entry->elapsed = 0.0; + entry->average = 0.0; + entry->maximum = 0.0; + entry->count = 0; } - /* SUNProfiler. @@ -138,11 +147,11 @@ static void sunResetTiming(sunTimerStruct* entry) struct _SUNProfiler { - void* comm; - char* title; - SUNHashMap map; + void* comm; + char* title; + SUNHashMap map; sunTimerStruct* overhead; - double sundials_time; + double sundials_time; }; int SUNProfiler_Create(void* comm, const char* title, SUNProfiler* p) @@ -151,23 +160,22 @@ int SUNProfiler_Create(void* comm, const char* title, SUNProfiler* p) int max_entries; char* max_entries_env; - *p = profiler = (SUNProfiler) malloc(sizeof(struct _SUNProfiler)); + *p = profiler = (SUNProfiler)malloc(sizeof(struct _SUNProfiler)); - if (profiler == NULL) - return(-1); + if (profiler == NULL) return (-1); profiler->overhead = sunTimerStructNew(); if (profiler->overhead == NULL) { free(profiler); *p = profiler = NULL; - return(-1); + return (-1); } sunStartTiming(profiler->overhead); /* Check to see if max entries env variable was set, and use if it was. */ - max_entries = 2560; + max_entries = 2560; max_entries_env = getenv("SUNPROFILER_MAX_ENTRIES"); if (max_entries_env) max_entries = atoi(max_entries_env); if (max_entries <= 0) max_entries = 2560; @@ -175,10 +183,10 @@ int SUNProfiler_Create(void* comm, const char* title, SUNProfiler* p) /* Create the hashmap used to store the timers */ if (SUNHashMap_New(max_entries, &profiler->map)) { - sunTimerStructFree((void*) profiler->overhead); + sunTimerStructFree((void*)profiler->overhead); free(profiler); *p = profiler = NULL; - return(-1); + return (-1); } /* Attach the comm, duplicating it if MPI is used. */ @@ -187,7 +195,7 @@ int SUNProfiler_Create(void* comm, const char* title, SUNProfiler* p) if (comm != NULL) { profiler->comm = malloc(sizeof(MPI_Comm)); - MPI_Comm_dup(*((MPI_Comm*) comm), (MPI_Comm*) profiler->comm); + MPI_Comm_dup(*((MPI_Comm*)comm), (MPI_Comm*)profiler->comm); } #else profiler->comm = comm; @@ -204,19 +212,19 @@ int SUNProfiler_Create(void* comm, const char* title, SUNProfiler* p) SUNDIALS_MARK_BEGIN(profiler, SUNDIALS_ROOT_TIMER); sunStopTiming(profiler->overhead); - return(0); + return (0); } int SUNProfiler_Free(SUNProfiler* p) { - if (p == NULL) return(-1); + if (p == NULL) return (-1); SUNDIALS_MARK_END(*p, SUNDIALS_ROOT_TIMER); if (*p) { SUNHashMap_Destroy(&(*p)->map, sunTimerStructFree); - sunTimerStructFree((void*) (*p)->overhead); + sunTimerStructFree((void*)(*p)->overhead); #if SUNDIALS_MPI_ENABLED if ((*p)->comm) { @@ -229,7 +237,7 @@ int SUNProfiler_Free(SUNProfiler* p) } *p = NULL; - return(0); + return (0); } int SUNProfiler_Begin(SUNProfiler p, const char* name) @@ -241,25 +249,27 @@ int SUNProfiler_Begin(SUNProfiler p, const char* name) char* errmsg; #endif - if (p == NULL) return(-1); + if (p == NULL) return (-1); sunStartTiming(p->overhead); - if (SUNHashMap_GetValue(p->map, name, (void**) &timer)) + if (SUNHashMap_GetValue(p->map, name, (void**)&timer)) { timer = sunTimerStructNew(); - ier = SUNHashMap_Insert(p->map, name, (void*) timer); + ier = SUNHashMap_Insert(p->map, name, (void*)timer); if (ier) { #ifdef SUNDIALS_DEBUG - slen = strlen(name); - errmsg = malloc(slen*sizeof(char)); - snprintf(errmsg, 128+slen, "(((( [ERROR] in SUNProfilerBegin: SUNHashMapInsert failed with code %d while inserting %s))))\n", ier, name); + slen = strlen(name); + errmsg = malloc(slen * sizeof(char)); + snprintf(errmsg, + 128 + slen, "(((( [ERROR] in SUNProfilerBegin: SUNHashMapInsert failed with code %d while inserting %s))))\n", + ier, name); SUNDIALS_DEBUG_PRINT(errmsg); free(errmsg); #endif sunTimerStructFree(timer); sunStopTiming(p->overhead); - return(-1); + return (-1); } } @@ -267,31 +277,31 @@ int SUNProfiler_Begin(SUNProfiler p, const char* name) sunStartTiming(timer); sunStopTiming(p->overhead); - return(0); + return (0); } int SUNProfiler_End(SUNProfiler p, const char* name) { sunTimerStruct* timer; - if (p == NULL) return(-1); + if (p == NULL) return (-1); sunStartTiming(p->overhead); - if (SUNHashMap_GetValue(p->map, name, (void**) &timer)) + if (SUNHashMap_GetValue(p->map, name, (void**)&timer)) { sunStopTiming(p->overhead); - return(-1); + return (-1); } sunStopTiming(timer); sunStopTiming(p->overhead); - return(0); + return (0); } int SUNProfiler_Reset(SUNProfiler p) { - int i = 0; + int i = 0; sunTimerStruct* timer = NULL; /* Check for valid input */ @@ -323,26 +333,26 @@ int SUNProfiler_Reset(SUNProfiler p) int SUNProfiler_Print(SUNProfiler p, FILE* fp) { - int i = 0; - int rank = 0; - sunTimerStruct* timer = NULL; + int i = 0; + int rank = 0; + sunTimerStruct* timer = NULL; SUNHashMapKeyValue* sorted = NULL; - if (p == NULL) return(-1); + if (p == NULL) return (-1); sunStartTiming(p->overhead); /* Get the total SUNDIALS time up to this point */ SUNDIALS_MARK_END(p, SUNDIALS_ROOT_TIMER); SUNDIALS_MARK_BEGIN(p, SUNDIALS_ROOT_TIMER); - if (SUNHashMap_GetValue(p->map, SUNDIALS_ROOT_TIMER, (void**) &timer)) - return(-1); + if (SUNHashMap_GetValue(p->map, SUNDIALS_ROOT_TIMER, (void**)&timer)) + return (-1); p->sundials_time = timer->elapsed; #if SUNDIALS_MPI_ENABLED if (p->comm) { - MPI_Comm_rank(*((MPI_Comm*) p->comm), &rank); + MPI_Comm_rank(*((MPI_Comm*)p->comm), &rank); /* Find the max and average time across all ranks */ sunCollectTimers(p); } @@ -350,26 +360,29 @@ int SUNProfiler_Print(SUNProfiler p, FILE* fp) if (rank == 0) { - struct timespec spec; + sunTimespec spec; /* Sort the timers in descending order */ - if (SUNHashMap_Sort(p->map, &sorted, sunCompareTimes)) - return(-1); + if (SUNHashMap_Sort(p->map, &sorted, sunCompareTimes)) return (-1); clock_getres(CLOCK_MONOTONIC, &spec); - fprintf(fp, "\n================================================================================================================\n"); + fprintf(fp, "\n============================================================" + "====================================================\n"); fprintf(fp, "SUNDIALS GIT VERSION: %s\n", SUNDIALS_GIT_VERSION); fprintf(fp, "SUNDIALS PROFILER: %s\n", p->title); - fprintf(fp, "TIMER RESOLUTION: %gs\n", 1e-9 * ((double) spec.tv_nsec)); - fprintf(fp, "%-40s\t %% time (inclusive) \t max/rank \t average/rank \t count \n", "RESULTS:"); - fprintf(fp, "================================================================================================================\n"); + fprintf(fp, "TIMER RESOLUTION: %gs\n", 1e-9 * ((double)spec.tv_nsec)); + fprintf(fp, "%-40s\t %% time (inclusive) \t max/rank \t average/rank \t count \n", + "RESULTS:"); + fprintf(fp, "==============================================================" + "==================================================\n"); #if SUNDIALS_MPI_ENABLED if (p->comm == NULL) - printf("WARNING: no MPI communicator provided, times shown are for rank 0\n"); + printf( + "WARNING: no MPI communicator provided, times shown are for rank 0\n"); #endif /* Print all the other timers out */ for (i = 0; i < p->map->size; i++) - if (sorted[i]) sunPrintTimers(i, sorted[i], fp, (void*) p); + if (sorted[i]) sunPrintTimers(i, sorted[i], fp, (void*)p); free(sorted); } @@ -378,24 +391,26 @@ int SUNProfiler_Print(SUNProfiler p, FILE* fp) if (rank == 0) { /* Print out the total time and the profiler overhead */ - fprintf(fp, "%-40s\t %6.2f%% \t %.6fs \t -- \t\t -- \n", "Est. profiler overhead", - p->overhead->elapsed/p->sundials_time, + fprintf(fp, "%-40s\t %6.2f%% \t %.6fs \t -- \t\t -- \n", + "Est. profiler overhead", p->overhead->elapsed / p->sundials_time, p->overhead->elapsed); /* End of output */ fprintf(fp, "\n"); } - return(0); + return (0); } #if SUNDIALS_MPI_ENABLED -static void sunTimerStructReduceMaxAndSum(void* a, void* b, int* len, MPI_Datatype* dType) +static void sunTimerStructReduceMaxAndSum(void* a, void* b, int* len, + MPI_Datatype* dType) { - sunTimerStruct* a_ts = (sunTimerStruct*) a; - sunTimerStruct* b_ts = (sunTimerStruct*) b; + sunTimerStruct* a_ts = (sunTimerStruct*)a; + sunTimerStruct* b_ts = (sunTimerStruct*)b; int i; - for (i = 0; i < *len; ++i) { + for (i = 0; i < *len; ++i) + { b_ts[i].average += a_ts[i].elapsed; b_ts[i].maximum = SUNMAX(a_ts[i].maximum, b_ts[i].maximum); } @@ -406,24 +421,24 @@ int sunCollectTimers(SUNProfiler p) { int i, rank, nranks; - MPI_Comm comm = *((MPI_Comm*) p->comm); + MPI_Comm comm = *((MPI_Comm*)p->comm); MPI_Comm_rank(comm, &rank); MPI_Comm_size(comm, &nranks); sunTimerStruct** values = NULL; /* Extract the elapsed times from the hash map */ - SUNHashMap_Values(p->map, (void***) &values, sizeof(sunTimerStruct)); - sunTimerStruct* reduced = (sunTimerStruct*) malloc(p->map->size*sizeof(sunTimerStruct)); - for (i = 0; i < p->map->size; ++i) - reduced[i] = *values[i]; + SUNHashMap_Values(p->map, (void***)&values, sizeof(sunTimerStruct)); + sunTimerStruct* reduced = + (sunTimerStruct*)malloc(p->map->size * sizeof(sunTimerStruct)); + for (i = 0; i < p->map->size; ++i) reduced[i] = *values[i]; /* Register MPI datatype for sunTimerStruct */ MPI_Datatype tmp_type, MPI_sunTimerStruct; - const int block_lens[2] = { 5, 1 }; - const MPI_Datatype types[2] = { MPI_DOUBLE, MPI_LONG }; - const MPI_Aint displ[2] = { offsetof(sunTimerStruct, tic), - offsetof(sunTimerStruct, count) }; + const int block_lens[2] = {5, 1}; + const MPI_Datatype types[2] = {MPI_DOUBLE, MPI_LONG}; + const MPI_Aint displ[2] = {offsetof(sunTimerStruct, tic), + offsetof(sunTimerStruct, count)}; MPI_Aint lb, extent; MPI_Type_create_struct(2, block_lens, displ, types, &tmp_type); @@ -454,15 +469,16 @@ int sunCollectTimers(SUNProfiler p) MPI_Op_free(&MPI_sunTimerStruct_MAXANDSUM); /* Update the values that are in this rank's hash map. */ - for (i = 0; i < p->map->size; ++i) { - values[i]->average = reduced[i].average / (realtype) nranks; + for (i = 0; i < p->map->size; ++i) + { + values[i]->average = reduced[i].average / (realtype)nranks; values[i]->maximum = reduced[i].maximum; } free(reduced); free(values); - return(0); + return (0); } #endif @@ -470,13 +486,15 @@ int sunCollectTimers(SUNProfiler p) max across ranks, average across ranks, and the timer counter. */ void sunPrintTimers(int idx, SUNHashMapKeyValue kv, FILE* fp, void* pvoid) { - SUNProfiler p = (SUNProfiler) pvoid; - sunTimerStruct* ts = (sunTimerStruct*) kv->value; - double maximum = ts->maximum; - double average = ts->average; - double percent = strcmp((const char*) kv->key, (const char*) SUNDIALS_ROOT_TIMER) ? maximum / p->sundials_time * 100 : 100; - fprintf(fp, "%-40s\t %6.2f%% \t %.6fs \t %.6fs \t %ld\n", - kv->key, percent, maximum, average, ts->count); + SUNProfiler p = (SUNProfiler)pvoid; + sunTimerStruct* ts = (sunTimerStruct*)kv->value; + double maximum = ts->maximum; + double average = ts->average; + double percent = strcmp((const char*)kv->key, (const char*)SUNDIALS_ROOT_TIMER) + ? maximum / p->sundials_time * 100 + : 100; + fprintf(fp, "%-40s\t %6.2f%% \t %.6fs \t %.6fs \t %ld\n", kv->key, + percent, maximum, average, ts->count); } /* Comparator for qsort that compares key-value pairs @@ -486,27 +504,22 @@ int sunCompareTimes(const void* l, const void* r) double left_max; double right_max; - const SUNHashMapKeyValue left = *((SUNHashMapKeyValue*) l); - const SUNHashMapKeyValue right = *((SUNHashMapKeyValue*) r); + const SUNHashMapKeyValue left = *((SUNHashMapKeyValue*)l); + const SUNHashMapKeyValue right = *((SUNHashMapKeyValue*)r); - if (left == NULL && right == NULL) - return(0); - if (left == NULL) - return(1); - if (right == NULL) - return(-1); + if (left == NULL && right == NULL) return (0); + if (left == NULL) return (1); + if (right == NULL) return (-1); - left_max = ((sunTimerStruct*) left->value)->maximum; - right_max = ((sunTimerStruct*) right->value)->maximum; + left_max = ((sunTimerStruct*)left->value)->maximum; + right_max = ((sunTimerStruct*)right->value)->maximum; - if (left_max < right_max) - return(1); - if (left_max > right_max) - return(-1); - return(0); + if (left_max < right_max) return (1); + if (left_max > right_max) return (-1); + return (0); } -int sunclock_gettime_monotonic(struct timespec* ts) +int sunclock_gettime_monotonic(sunTimespec* ts) { #if (defined(WIN32) || defined(_WIN32)) && !defined(SUNDIALS_HAVE_POSIX_TIMERS) static long ticks_per_sec; From 68100ad9a9a40d6c1d66b7ec8114766cfeb7a3be Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Fri, 11 Aug 2023 14:49:28 -0700 Subject: [PATCH 09/36] use LARGE_INTEGER --- src/sundials/sundials_profiler.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index e4c11a32d5..901062328e 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -363,12 +363,16 @@ int SUNProfiler_Print(SUNProfiler p, FILE* fp) sunTimespec spec; /* Sort the timers in descending order */ if (SUNHashMap_Sort(p->map, &sorted, sunCompareTimes)) return (-1); +#if defined(SUNDIALS_HAVE_POSIX_TIMERS) clock_getres(CLOCK_MONOTONIC, &spec); +#endif fprintf(fp, "\n============================================================" "====================================================\n"); fprintf(fp, "SUNDIALS GIT VERSION: %s\n", SUNDIALS_GIT_VERSION); fprintf(fp, "SUNDIALS PROFILER: %s\n", p->title); +#if defined(SUNDIALS_HAVE_POSIX_TIMERS) fprintf(fp, "TIMER RESOLUTION: %gs\n", 1e-9 * ((double)spec.tv_nsec)); +#endif fprintf(fp, "%-40s\t %% time (inclusive) \t max/rank \t average/rank \t count \n", "RESULTS:"); fprintf(fp, "==============================================================" @@ -522,8 +526,8 @@ int sunCompareTimes(const void* l, const void* r) int sunclock_gettime_monotonic(sunTimespec* ts) { #if (defined(WIN32) || defined(_WIN32)) && !defined(SUNDIALS_HAVE_POSIX_TIMERS) - static long ticks_per_sec; - long ticks; + static LARGE_INTEGER ticks_per_sec; + LARGE_INTEGER ticks; if (!ticks_per_sec.QuadPart) { From 5626cf54d7f2d5bdbc575187a888888236b0ad5f Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Fri, 11 Aug 2023 15:19:18 -0700 Subject: [PATCH 10/36] add missing windows system includes --- src/sundials/sundials_profiler.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index 901062328e..823f4164e7 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -29,6 +29,9 @@ #include #elif !(defined(WIN32) || defined(_WIN32)) #error POSIX is needed for clock_getttime +#else +#include +#include #endif #include @@ -360,7 +363,9 @@ int SUNProfiler_Print(SUNProfiler p, FILE* fp) if (rank == 0) { +#if defined(SUNDIALS_HAVE_POSIX_TIMERS) sunTimespec spec; +#endif /* Sort the timers in descending order */ if (SUNHashMap_Sort(p->map, &sorted, sunCompareTimes)) return (-1); #if defined(SUNDIALS_HAVE_POSIX_TIMERS) @@ -534,7 +539,6 @@ int sunclock_gettime_monotonic(sunTimespec* ts) QueryPerformanceFrequency(&ticks_per_sec); if (!ticks_per_sec.QuadPart) { - errno = ENOTSUP; return -1; } } From b8b02b3663d24a1849e56d028f86388b06e68969 Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Fri, 11 Aug 2023 15:25:05 -0700 Subject: [PATCH 11/36] update changelog --- CHANGELOG.md | 4 ++++ doc/arkode/guide/source/Introduction.rst | 4 +++- doc/cvode/guide/source/Introduction.rst | 3 +++ doc/cvodes/guide/source/Introduction.rst | 3 +++ doc/ida/guide/source/Introduction.rst | 3 +++ doc/idas/guide/source/Introduction.rst | 3 +++ doc/kinsol/guide/source/Introduction.rst | 3 +++ 7 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cf25b99bf6..6e402c06f3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,10 @@ and fixed the targets used for rocBLAS and rocSPARSE. Added the fourth order ERK method `ARKODE_SOFRONIOU_SPALETTA_5_3_4`. +Changed the `SUNProfiler` so that it does not rely on `MPI_WTime` in any case. +This fixes https://github.com/LLNL/sundials/issues/312. + + ## Changes to SUNDIALS in release 6.6.1 Updated the Tpetra NVector interface to support Trilinos 14. diff --git a/doc/arkode/guide/source/Introduction.rst b/doc/arkode/guide/source/Introduction.rst index 7fbe137950..50fdfb5f4b 100644 --- a/doc/arkode/guide/source/Introduction.rst +++ b/doc/arkode/guide/source/Introduction.rst @@ -158,6 +158,9 @@ CMake targets. Added the fourth order ERK method ``ARKODE_SOFRONIOU_SPALETTA_5_3_4``. +Changed the ``SUNProfiler`` so that it does not rely on ``MPI_WTime`` in any case. +This fixes `GitHub Issue #312 `_. + Changes in v5.6.1 ----------------- @@ -987,7 +990,6 @@ utilize a zero initial guess. A bug was fixed in the ARKODE stepper modules where the stop time may be passed after resetting the integrator. - Changes in v4.7.0 ----------------- diff --git a/doc/cvode/guide/source/Introduction.rst b/doc/cvode/guide/source/Introduction.rst index b28e54a07a..6b50203d52 100644 --- a/doc/cvode/guide/source/Introduction.rst +++ b/doc/cvode/guide/source/Introduction.rst @@ -129,6 +129,9 @@ Fixed scaling bug in ``SUNMatScaleAddI_Sparse`` for non-square matrices. Fixed missing soversions in some ``SUNLinearSolver`` and ``SUNNonlinearSolver`` CMake targets. +Changed the ``SUNProfiler`` so that it does not rely on ``MPI_WTime`` in any case. +This fixes `GitHub Issue #312 `_. + Changes in v6.6.1 ----------------- diff --git a/doc/cvodes/guide/source/Introduction.rst b/doc/cvodes/guide/source/Introduction.rst index 567c0b0284..122010be94 100644 --- a/doc/cvodes/guide/source/Introduction.rst +++ b/doc/cvodes/guide/source/Introduction.rst @@ -132,6 +132,9 @@ Fixed scaling bug in ``SUNMatScaleAddI_Sparse`` for non-square matrices. Fixed missing soversions in some ``SUNLinearSolver`` and ``SUNNonlinearSolver`` CMake targets. +Changed the ``SUNProfiler`` so that it does not rely on ``MPI_WTime`` in any case. +This fixes `GitHub Issue #312 `_. + Changes in v6.6.1 ----------------- diff --git a/doc/ida/guide/source/Introduction.rst b/doc/ida/guide/source/Introduction.rst index 5fae985f15..00a0fbcdde 100644 --- a/doc/ida/guide/source/Introduction.rst +++ b/doc/ida/guide/source/Introduction.rst @@ -90,6 +90,9 @@ Fixed scaling bug in ``SUNMatScaleAddI_Sparse`` for non-square matrices. Fixed missing soversions in some ``SUNLinearSolver`` and ``SUNNonlinearSolver`` CMake targets. +Changed the ``SUNProfiler`` so that it does not rely on ``MPI_WTime`` in any case. +This fixes `GitHub Issue #312 `_. + Changes in v6.6.1 ----------------- diff --git a/doc/idas/guide/source/Introduction.rst b/doc/idas/guide/source/Introduction.rst index 4d1d3b3c4c..9087a045bc 100644 --- a/doc/idas/guide/source/Introduction.rst +++ b/doc/idas/guide/source/Introduction.rst @@ -107,6 +107,9 @@ Fixed scaling bug in ``SUNMatScaleAddI_Sparse`` for non-square matrices. Fixed missing soversions in some ``SUNLinearSolver`` and ``SUNNonlinearSolver`` CMake targets. +Changed the ``SUNProfiler`` so that it does not rely on ``MPI_WTime`` in any case. +This fixes `GitHub Issue #312 `_. + Changes in v5.6.1 ----------------- diff --git a/doc/kinsol/guide/source/Introduction.rst b/doc/kinsol/guide/source/Introduction.rst index d91d300fbb..da60807450 100644 --- a/doc/kinsol/guide/source/Introduction.rst +++ b/doc/kinsol/guide/source/Introduction.rst @@ -110,6 +110,9 @@ Updated the Tpetra NVector interface to support Trilinos 14. Fixed a memory leak when destroying a CUDA, HIP, SYCL, or system SUNMemoryHelper object. +Changed the ``SUNProfiler`` so that it does not rely on ``MPI_WTime`` in any case. +This fixes `GitHub Issue #312 `_. + Changes in v6.6.0 ----------------- From a20e575a01a556fd468e9cc4c5d192f43687d11f Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Tue, 5 Sep 2023 08:58:28 -0700 Subject: [PATCH 12/36] need windows.h --- src/sundials/sundials_profiler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index 823f4164e7..e1618f3cb3 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -30,6 +30,7 @@ #elif !(defined(WIN32) || defined(_WIN32)) #error POSIX is needed for clock_getttime #else +#include #include #include #endif From 2d655353658c8f3e4d2668bd2f2a18ff41327fbf Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Tue, 5 Sep 2023 13:23:59 -0700 Subject: [PATCH 13/36] ticks in microseconds --- src/sundials/sundials_profiler.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index e1618f3cb3..aafd4391d4 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -546,9 +546,11 @@ int sunclock_gettime_monotonic(sunTimespec* ts) QueryPerformanceCounter(&ticks); + /* QueryPerformanceCounter is ticks in microseconds */ + ts->tv_sec = (long)(ticks.QuadPart / ticks_per_sec.QuadPart); - ts->tv_nsec = (long)(((ticks.QuadPart % ticks_per_sec.QuadPart) * 1000000000) / - ticks_per_sec.QuadPart); + ts->tv_nsec = (long)(((ticks.QuadPart % ticks_per_sec.QuadPart) * 1000000) / + ticks_per_sec.QuadPart); return 0; #else From 1a1c4a795d0ac4b724d16edc734baa4e631abecb Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Tue, 5 Sep 2023 13:30:05 -0700 Subject: [PATCH 14/36] add profiling test --- test/unit_tests/CMakeLists.txt | 1 + test/unit_tests/profiling/CMakeLists.txt | 60 +++++++ test/unit_tests/profiling/test_profiling.cpp | 173 +++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 test/unit_tests/profiling/CMakeLists.txt create mode 100644 test/unit_tests/profiling/test_profiling.cpp diff --git a/test/unit_tests/CMakeLists.txt b/test/unit_tests/CMakeLists.txt index fce631573e..6ccf7e567f 100644 --- a/test/unit_tests/CMakeLists.txt +++ b/test/unit_tests/CMakeLists.txt @@ -42,5 +42,6 @@ endif() if(CXX_FOUND) add_subdirectory(reductions) + add_subdirectory(profiling) add_subdirectory(sunmemory) endif() diff --git a/test/unit_tests/profiling/CMakeLists.txt b/test/unit_tests/profiling/CMakeLists.txt new file mode 100644 index 0000000000..c29a6f2afe --- /dev/null +++ b/test/unit_tests/profiling/CMakeLists.txt @@ -0,0 +1,60 @@ +# ------------------------------------------------------------------------------ +# Programmer(s): David J. Gardner @ LLNL +# ------------------------------------------------------------------------------ +# SUNDIALS Copyright Start +# Copyright (c) 2002-2022, Lawrence Livermore National Security +# and Southern Methodist University. +# All rights reserved. +# +# See the top-level LICENSE and NOTICE files for details. +# +# SPDX-License-Identifier: BSD-3-Clause +# SUNDIALS Copyright End +# ------------------------------------------------------------------------------ + +# List of test tuples of the form "name\;args" +set(unit_tests "test_profiling\;") + +# Add the build and install targets for each test +foreach(test_tuple ${unit_tests}) + + # parse the test tuple + list(GET test_tuple 0 test) + list(GET test_tuple 1 test_args) + + # check if this test has already been added, only need to add + # test source files once for testing with different inputs + if(NOT TARGET ${test}) + + # test source files + add_executable(${test} ${test}.cpp) + + set_target_properties(${test} PROPERTIES FOLDER "unit_tests") + + # include location of public and private header files + target_include_directories(${test} PRIVATE + $ + ${CMAKE_SOURCE_DIR}/include + ${CMAKE_SOURCE_DIR}/src) + + # libraries to link against + target_link_libraries(${test} + sundials_generic + ${EXE_EXTRA_LINK_LIBS}) + + endif() + + # check if test args are provided and set the test name + if("${test_args}" STREQUAL "") + set(test_name ${test}) + else() + string(REPLACE " " "_" test_name "${test}_${test_args}") + string(REPLACE " " ";" test_args "${test_args}") + endif() + + # add test to regression tests + add_test(NAME ${test_name} COMMAND ${test} ${test_args}) + +endforeach() + +message(STATUS "Added profiling units tests") diff --git a/test/unit_tests/profiling/test_profiling.cpp b/test/unit_tests/profiling/test_profiling.cpp new file mode 100644 index 0000000000..d3cc8315dc --- /dev/null +++ b/test/unit_tests/profiling/test_profiling.cpp @@ -0,0 +1,173 @@ +/* ----------------------------------------------------------------------------- + * Programmer(s): David J. Gardner @ LLNL + * ----------------------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2022, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * ---------------------------------------------------------------------------*/ + +#include +#include +#include +#include +#include +#include + +#include "sundials/sundials_profiler.h" +#include "sundials/sundials_types.h" + +int sleep(SUNProfiler prof, int sec) +{ + int flag = SUNProfiler_Begin(prof, "sleep"); + if (flag) return flag; + std::this_thread::sleep_for(std::chrono::seconds(sec)); + flag = SUNProfiler_End(prof, "sleep"); + if (flag) return flag; + return 0; +} + +int print_timings(SUNProfiler prof) +{ + // Output timing in default (table) format + int flag = SUNProfiler_Print(prof, stdout); + if (flag) + { + std::cerr << "SUNProfiler_Print returned " << flag << "\n"; + return 1; + } + + flag = SUNProfiler_Print(prof, stdout); + if (flag) + { + std::cerr << "SUNProfiler_Print returned " << flag << "\n"; + return 1; + } + + return 0; +} + +int main() +{ + // ----- + // Setup + // ----- + + std::cout << "Testing SUNProfiler\n"; + + SUNProfiler prof = nullptr; + int flag = SUNProfiler_Create(nullptr, "SUNProfiler Test", &prof); + if (flag) + { + std::cerr << "SUNProfiler_Create returned " << flag << "\n"; + return 1; + } + + // ------ + // Test 1 + // ------ + + std::cout << "\nTest 1: sleep 1s, print timings \n"; + + flag = sleep(prof, 1); + if (flag) + { + std::cerr << "sleep returned " << flag << "\n"; + return 1; + } + + flag = print_timings(prof); + if (flag) + { + std::cerr << "print_timings returned " << flag << "\n"; + return 1; + } + + // ------ + // Test 2 + // ------ + + std::cout << "\nTest 2: reset, sleep 2s, print timings\n"; + + // Reset timing + flag = SUNProfiler_Reset(prof); + if (flag) + { + std::cerr << "SUNProfiler_Reset returned " << flag << "\n"; + return 1; + } + + flag = sleep(prof, 2); + if (flag) + { + std::cerr << "sleep returned " << flag << "\n"; + return 1; + } + + flag = print_timings(prof); + if (flag) + { + std::cerr << "print_timings returned " << flag << "\n"; + return 1; + } + + // ------ + // Test 3 + // ------ + + std::cout << "\nTest 3: multiple outputs to a file for plot test\n"; + + std::FILE* fout = std::fopen("profiling_test_output.txt", "w"); + if (!fout) + { + std::cerr << "fopen returned a null pointer\n"; + return 1; + } + + for (int i = 1; i < 4; i++) + { + // Reset timing + flag = SUNProfiler_Reset(prof); + if (flag) + { + std::cerr << "SUNProfiler_Reset returned " << flag << "\n"; + return 1; + } + + flag = sleep(prof, i); + if (flag) + { + std::cerr << "sleep returned " << flag << "\n"; + return 1; + } + + flag = SUNProfiler_Print(prof, fout); + if (flag) + { + std::cerr << "SUNProfiler_Print returned " << flag << "\n"; + return 1; + } + } + + std::fclose(fout); + + // -------- + // Clean up + // -------- + + flag = SUNProfiler_Free(&prof); + if (flag) + { + std::cerr << "SUNProfiler_Free returned " << flag << "\n"; + return 1; + } + + std::cout << "\nTest complete\n"; + + return 0; +} From 884541f10216d3810110f8e714ec1a83378c0035 Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Tue, 5 Sep 2023 13:36:01 -0700 Subject: [PATCH 15/36] enable unit tests in Windows short test --- .github/workflows/windows-latest-mingw.yml | 2 +- .github/workflows/windows-latest.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows-latest-mingw.yml b/.github/workflows/windows-latest-mingw.yml index 4ea9269788..6a77075105 100644 --- a/.github/workflows/windows-latest-mingw.yml +++ b/.github/workflows/windows-latest-mingw.yml @@ -21,7 +21,7 @@ jobs: - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -G "MinGW Makefiles" -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DSUNDIALS_BUILD_WITH_PROFILING=ON -DSUNDIALS_LOGGING_LEVEL=2 + run: cmake -G "MinGW Makefiles" -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DSUNDIALS_BUILD_WITH_PROFILING=ON -DSUNDIALS_LOGGING_LEVEL=2 -DSUNDIALS_TEST_UNITTESTS=ON -DEXAMPLES_ENABLE_CXX=ON - name: Build # Build your program with the given configuration diff --git a/.github/workflows/windows-latest.yml b/.github/workflows/windows-latest.yml index 8103c6df1a..d640eb6bd2 100644 --- a/.github/workflows/windows-latest.yml +++ b/.github/workflows/windows-latest.yml @@ -17,7 +17,7 @@ jobs: - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_STATIC_LIBS=OFF -DSUNDIALS_BUILD_WITH_PROFILING=ON -DSUNDIALS_LOGGING_LEVEL=2 + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DBUILD_STATIC_LIBS=OFF -DSUNDIALS_BUILD_WITH_PROFILING=ON -DSUNDIALS_LOGGING_LEVEL=2 -DSUNDIALS_TEST_UNITTESTS=ON -DEXAMPLES_ENABLE_CXX=ON - name: Build # Build your program with the given configuration From 21c3da4f520626a9e4e593c1d42cf7bfede78dc2 Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Fri, 27 Oct 2023 12:18:24 -0700 Subject: [PATCH 16/36] remove commented out code --- cmake/SundialsSetupCompilers.cmake | 7 ------- 1 file changed, 7 deletions(-) diff --git a/cmake/SundialsSetupCompilers.cmake b/cmake/SundialsSetupCompilers.cmake index 2c52b4b406..b993ec85f5 100644 --- a/cmake/SundialsSetupCompilers.cmake +++ b/cmake/SundialsSetupCompilers.cmake @@ -223,13 +223,6 @@ if(SUNDIALS_POSIX_TIMERS AND POSIX_TIMERS_NEED_POSIX_C_SOURCE) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_POSIX_C_SOURCE=${SUNDIALS_POSIX_C_SOURCE}") endif() -# # Check if profiling is being built with no timers. -# if(SUNDIALS_BUILD_WITH_PROFILING AND -# (NOT ENABLE_CALIPER) AND -# (NOT ENABLE_MPI) AND -# (NOT SUNDIALS_POSIX_TIMERS)) -# message(SEND_ERROR "The SUNDIALS native profiler requires POSIX timers or MPI_Wtime, but neither were found.") -# endif() # --------------------------------------------------------------- # Check for deprecated attribute with message From 90717c970e24c44e83ca3d5b520f3944c56d2337 Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Fri, 27 Oct 2023 12:22:59 -0700 Subject: [PATCH 17/36] add unit tests of profiler to tarscript --- scripts/shared | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/shared b/scripts/shared index 7304bc5df8..0cc32e4ed9 100755 --- a/scripts/shared +++ b/scripts/shared @@ -838,3 +838,4 @@ echo " --- Add unit tests files to $tarfile" $tar $tarfile $distrobase/test/unit_tests/CMakeLists.txt $tar $tarfile $distrobase/test/unit_tests/reductions $tar $tarfile $distrobase/test/unit_tests/sunmemory +$tar $tarfile $distrobase/test/unit_tests/profiling From ec30aea6ee9400d22271ffe1af1c54f7e690ddd8 Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Fri, 27 Oct 2023 12:41:08 -0700 Subject: [PATCH 18/36] organize src targets for windows --- cmake/macros/SundialsAddLibrary.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/macros/SundialsAddLibrary.cmake b/cmake/macros/SundialsAddLibrary.cmake index 96d71765ec..5bf25ab4b8 100644 --- a/cmake/macros/SundialsAddLibrary.cmake +++ b/cmake/macros/SundialsAddLibrary.cmake @@ -152,6 +152,8 @@ macro(sundials_add_library target) # create the target for the object library add_library(${obj_target} OBJECT ${sources}) + set_target_properties(${obj_target} PROPERTIES FOLDER "obj") + # add all object libraries to object library if(sundials_add_library_OBJECT_LIBRARIES) target_link_libraries(${obj_target} @@ -229,6 +231,8 @@ macro(sundials_add_library target) add_library(${_actual_target_name} ${_libtype} $) + set_target_properties(${_actual_target_name} PROPERTIES FOLDER "src") + # add any object library dependencies if(sundials_add_library_OBJECT_LIBRARIES) if(${_libtype} MATCHES "STATIC") From 21006fe3b84e15eb14b62d421c4d297d68e8c2f8 Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Fri, 27 Oct 2023 13:39:33 -0700 Subject: [PATCH 19/36] add get functions --- include/sundials/sundials_profiler.h | 39 ++++--- src/sundials/sundials_profiler.c | 51 +++++++-- test/unit_tests/profiling/test_profiling.cpp | 114 +++++++++++++++---- 3 files changed, 158 insertions(+), 46 deletions(-) diff --git a/include/sundials/sundials_profiler.h b/include/sundials/sundials_profiler.h index f50b7b761c..f793f31b36 100644 --- a/include/sundials/sundials_profiler.h +++ b/include/sundials/sundials_profiler.h @@ -23,16 +23,21 @@ #include "caliper/cali.h" #endif -#ifdef __cplusplus /* wrapper to enable C++ usage */ +#ifdef __cplusplus /* wrapper to enable C++ usage */ extern "C" { #endif -typedef struct _SUNProfiler *SUNProfiler; +typedef struct _SUNProfiler* SUNProfiler; -SUNDIALS_EXPORT int SUNProfiler_Create(void* comm, const char* title, SUNProfiler* p); +SUNDIALS_EXPORT int SUNProfiler_Create(void* comm, const char* title, + SUNProfiler* p); SUNDIALS_EXPORT int SUNProfiler_Free(SUNProfiler* p); SUNDIALS_EXPORT int SUNProfiler_Begin(SUNProfiler p, const char* name); SUNDIALS_EXPORT int SUNProfiler_End(SUNProfiler p, const char* name); +SUNDIALS_EXPORT int SUNProfiler_GetTimerResolution(SUNProfiler p, + double* resolution); +SUNDIALS_EXPORT int SUNProfiler_GetElapsedTime(SUNProfiler p, const char* name, + double* time); SUNDIALS_EXPORT int SUNProfiler_Print(SUNProfiler p, FILE* fp); SUNDIALS_EXPORT int SUNProfiler_Reset(SUNProfiler p); @@ -42,7 +47,8 @@ SUNDIALS_EXPORT int SUNProfiler_Reset(SUNProfiler p); #define SUNDIALS_MARK_FUNCTION_END(profobj) CALI_MARK_FUNCTION_END -#define SUNDIALS_WRAP_STATEMENT(profobj, name, stmt) CALI_WRAP_STATEMENT(name, stmt) +#define SUNDIALS_WRAP_STATEMENT(profobj, name, stmt) \ + CALI_WRAP_STATEMENT(name, stmt) #define SUNDIALS_MARK_BEGIN(profobj, name) CALI_MARK_BEGIN(name) @@ -54,21 +60,23 @@ SUNDIALS_EXPORT int SUNProfiler_Reset(SUNProfiler p); #elif defined(SUNDIALS_BUILD_WITH_PROFILING) -#define SUNDIALS_MARK_FUNCTION_BEGIN(profobj) SUNProfiler_Begin(profobj, __func__) +#define SUNDIALS_MARK_FUNCTION_BEGIN(profobj) \ + SUNProfiler_Begin(profobj, __func__) #define SUNDIALS_MARK_FUNCTION_END(profobj) SUNProfiler_End(profobj, __func__) #define SUNDIALS_WRAP_STATEMENT(profobj, name, stmt) \ - SUNProfiler_Begin(profobj, (name)); \ - stmt; \ - SUNProfiler_End(profobj, (name)); + SUNProfiler_Begin(profobj, (name)); \ + stmt; \ + SUNProfiler_End(profobj, (name)); #define SUNDIALS_MARK_BEGIN(profobj, name) SUNProfiler_Begin(profobj, (name)) #define SUNDIALS_MARK_END(profobj, name) SUNProfiler_End(profobj, (name)) #ifdef __cplusplus -#define SUNDIALS_CXX_MARK_FUNCTION(profobj) sundials::ProfilerMarkScope __ProfilerMarkScope(profobj, __func__) +#define SUNDIALS_CXX_MARK_FUNCTION(profobj) \ + sundials::ProfilerMarkScope __ProfilerMarkScope(profobj, __func__) #endif #else @@ -92,27 +100,26 @@ SUNDIALS_EXPORT int SUNProfiler_Reset(SUNProfiler p); #ifdef __cplusplus } -namespace sundials -{ +namespace sundials { /* Convenience class for C++ codes. Allows for simpler profiler statements using C++ scoping rules. */ class ProfilerMarkScope { public: - ProfilerMarkScope(SUNProfiler prof, const char* name) { + ProfilerMarkScope(SUNProfiler prof, const char* name) + { prof_ = prof; name_ = name; SUNProfiler_Begin(prof_, name_); } - ~ProfilerMarkScope() { - SUNProfiler_End(prof_, name_); - } + ~ProfilerMarkScope() { SUNProfiler_End(prof_, name_); } + private: SUNProfiler prof_; const char* name_; }; -} +} // namespace sundials #endif #endif /* SUNDIALS_PROFILER_H_ */ diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index aafd4391d4..4cf2141881 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -30,9 +30,9 @@ #elif !(defined(WIN32) || defined(_WIN32)) #error POSIX is needed for clock_getttime #else +#include #include #include -#include #endif #include @@ -42,7 +42,7 @@ #include "sundials_debug.h" #include "sundials_hashmap.h" -#include "sundials_utils.h" +// #include "sundials_utils.h" #define SUNDIALS_ROOT_TIMER ((const char*)"From profiler epoch") @@ -303,6 +303,44 @@ int SUNProfiler_End(SUNProfiler p, const char* name) return (0); } +int SUNProfiler_GetTimerResolution(SUNProfiler p, double* resolution) +{ +#if defined(SUNDIALS_HAVE_POSIX_TIMERS) + sunTimespec spec; + clock_getres(CLOCK_MONOTONIC, &spec); + *resolution = 1e-9 * ((double)spec.tv_nsec); + + return (0); +#elif (defined(WIN32) || defined(_WIN32)) && \ + !defined(SUNDIALS_HAVE_POSIX_TIMERS) + static LARGE_INTEGER ticks_per_sec; + LARGE_INTEGER ticks; + + if (!ticks_per_sec.QuadPart) + { + QueryPerformanceFrequency(&ticks_per_sec); + if (!ticks_per_sec.QuadPart) { return -1; } + } + + *resolution = SUN_RCONST(1.0) / ticks_per_sec.QuadPart; + + return (0); +#else + return (-1); +#endif +} + +int SUNProfiler_GetElapsedTime(SUNProfiler p, const char* name, double* time) +{ + sunTimerStruct* timer; + + if (SUNHashMap_GetValue(p->map, name, (void**)&timer)) { return (-1); } + + *time = timer->elapsed; + + return (0); +} + int SUNProfiler_Reset(SUNProfiler p) { int i = 0; @@ -481,7 +519,7 @@ int sunCollectTimers(SUNProfiler p) /* Update the values that are in this rank's hash map. */ for (i = 0; i < p->map->size; ++i) { - values[i]->average = reduced[i].average / (realtype)nranks; + values[i]->average = reduced[i].average / (double)nranks; values[i]->maximum = reduced[i].maximum; } @@ -538,10 +576,7 @@ int sunclock_gettime_monotonic(sunTimespec* ts) if (!ticks_per_sec.QuadPart) { QueryPerformanceFrequency(&ticks_per_sec); - if (!ticks_per_sec.QuadPart) - { - return -1; - } + if (!ticks_per_sec.QuadPart) { return -1; } } QueryPerformanceCounter(&ticks); @@ -550,7 +585,7 @@ int sunclock_gettime_monotonic(sunTimespec* ts) ts->tv_sec = (long)(ticks.QuadPart / ticks_per_sec.QuadPart); ts->tv_nsec = (long)(((ticks.QuadPart % ticks_per_sec.QuadPart) * 1000000) / - ticks_per_sec.QuadPart); + ticks_per_sec.QuadPart); return 0; #else diff --git a/test/unit_tests/profiling/test_profiling.cpp b/test/unit_tests/profiling/test_profiling.cpp index d3cc8315dc..45e59e655d 100644 --- a/test/unit_tests/profiling/test_profiling.cpp +++ b/test/unit_tests/profiling/test_profiling.cpp @@ -12,23 +12,29 @@ * SUNDIALS Copyright End * ---------------------------------------------------------------------------*/ +#include +#include #include #include #include -#include #include -#include +#include "sundials/sundials_math.h" #include "sundials/sundials_profiler.h" #include "sundials/sundials_types.h" -int sleep(SUNProfiler prof, int sec) +int sleep(SUNProfiler prof, int sec, double* chrono) { + std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); int flag = SUNProfiler_Begin(prof, "sleep"); if (flag) return flag; std::this_thread::sleep_for(std::chrono::seconds(sec)); flag = SUNProfiler_End(prof, "sleep"); if (flag) return flag; + std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); + *chrono = + std::chrono::duration_cast(end - begin).count() * + 1e-9; return 0; } @@ -38,14 +44,16 @@ int print_timings(SUNProfiler prof) int flag = SUNProfiler_Print(prof, stdout); if (flag) { - std::cerr << "SUNProfiler_Print returned " << flag << "\n"; + std::cerr << ">>> FAILURE: " + << "SUNProfiler_Print returned " << flag << "\n"; return 1; } flag = SUNProfiler_Print(prof, stdout); if (flag) { - std::cerr << "SUNProfiler_Print returned " << flag << "\n"; + std::cerr << ">>> FAILURE: " + << "SUNProfiler_Print returned " << flag << "\n"; return 1; } @@ -58,13 +66,16 @@ int main() // Setup // ----- + double chrono; + std::cout << "Testing SUNProfiler\n"; SUNProfiler prof = nullptr; - int flag = SUNProfiler_Create(nullptr, "SUNProfiler Test", &prof); + int flag = SUNProfiler_Create(nullptr, "SUNProfiler Test", &prof); if (flag) { - std::cerr << "SUNProfiler_Create returned " << flag << "\n"; + std::cerr << ">>> FAILURE: " + << "SUNProfiler_Create returned " << flag << "\n"; return 1; } @@ -72,19 +83,46 @@ int main() // Test 1 // ------ - std::cout << "\nTest 1: sleep 1s, print timings \n"; + std::cout << "\nTest 1: sleep 1s, check timings \n"; - flag = sleep(prof, 1); + flag = sleep(prof, 1, &chrono); if (flag) { - std::cerr << "sleep returned " << flag << "\n"; + std::cerr << ">>> FAILURE: " + << "sleep returned " << flag << "\n"; return 1; } flag = print_timings(prof); if (flag) { - std::cerr << "print_timings returned " << flag << "\n"; + std::cerr << ">>> FAILURE: " + << "print_timings returned " << flag << "\n"; + return 1; + } + + double time, resolution; + flag = SUNProfiler_GetElapsedTime(prof, "sleep", &time); + if (flag) + { + std::cerr << ">>> FAILURE: " + << "SUNProfiler_GetElapsedTime returned " << flag << "\n"; + return 1; + } + + flag = SUNProfiler_GetTimerResolution(prof, &resolution); + if (flag) + { + std::cerr << ">>> FAILURE: " + << "SUNProfiler_GetTimerResolution returned " << flag << "\n"; + return 1; + } + + if (SUNRCompareTol(time, chrono, 10*resolution)) + { + std::cerr << ">>> FAILURE: " + << "time recorded was " << time << "s, but expected " << chrono + << " +/- " << resolution << "\n"; return 1; } @@ -98,21 +136,48 @@ int main() flag = SUNProfiler_Reset(prof); if (flag) { - std::cerr << "SUNProfiler_Reset returned " << flag << "\n"; + std::cerr << ">>> FAILURE: " + << "SUNProfiler_Reset returned " << flag << "\n"; return 1; } - flag = sleep(prof, 2); + flag = sleep(prof, 2, &chrono); if (flag) { - std::cerr << "sleep returned " << flag << "\n"; + std::cerr << ">>> FAILURE: " + << "sleep returned " << flag << "\n"; return 1; } flag = print_timings(prof); if (flag) { - std::cerr << "print_timings returned " << flag << "\n"; + std::cerr << ">>> FAILURE: " + << "print_timings returned " << flag << "\n"; + return 1; + } + + flag = SUNProfiler_GetElapsedTime(prof, "sleep", &time); + if (flag) + { + std::cerr << ">>> FAILURE: " + << "SUNProfiler_GetElapsedTime returned " << flag << "\n"; + return 1; + } + + flag = SUNProfiler_GetTimerResolution(prof, &resolution); + if (flag) + { + std::cerr << ">>> FAILURE: " + << "SUNProfiler_GetTimerResolution returned " << flag << "\n"; + return 1; + } + + if (SUNRCompareTol(time, chrono, 10*resolution)) + { + std::cerr << ">>> FAILURE: " + << "time recorded was " << time << "s, but expected " << chrono + << " +/- " << resolution << "\n"; return 1; } @@ -125,7 +190,8 @@ int main() std::FILE* fout = std::fopen("profiling_test_output.txt", "w"); if (!fout) { - std::cerr << "fopen returned a null pointer\n"; + std::cerr << ">>> FAILURE: " + << "fopen returned a null pointer\n"; return 1; } @@ -135,21 +201,24 @@ int main() flag = SUNProfiler_Reset(prof); if (flag) { - std::cerr << "SUNProfiler_Reset returned " << flag << "\n"; + std::cerr << ">>> FAILURE: " + << "SUNProfiler_Reset returned " << flag << "\n"; return 1; } - flag = sleep(prof, i); + flag = sleep(prof, i, &chrono); if (flag) { - std::cerr << "sleep returned " << flag << "\n"; + std::cerr << ">>> FAILURE: " + << "sleep returned " << flag << "\n"; return 1; } flag = SUNProfiler_Print(prof, fout); if (flag) { - std::cerr << "SUNProfiler_Print returned " << flag << "\n"; + std::cerr << ">>> FAILURE: " + << "SUNProfiler_Print returned " << flag << "\n"; return 1; } } @@ -163,11 +232,12 @@ int main() flag = SUNProfiler_Free(&prof); if (flag) { - std::cerr << "SUNProfiler_Free returned " << flag << "\n"; + std::cerr << ">>> FAILURE: " + << "SUNProfiler_Free returned " << flag << "\n"; return 1; } - std::cout << "\nTest complete\n"; + std::cout << "\nSUCCESS - test complete\n"; return 0; } From b61c7cba1264c1b6cc6913e263681f900d00ee69 Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Fri, 27 Oct 2023 14:02:51 -0700 Subject: [PATCH 20/36] only test profiling if enabled --- test/unit_tests/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/unit_tests/CMakeLists.txt b/test/unit_tests/CMakeLists.txt index 6ccf7e567f..77cfb20cad 100644 --- a/test/unit_tests/CMakeLists.txt +++ b/test/unit_tests/CMakeLists.txt @@ -42,6 +42,8 @@ endif() if(CXX_FOUND) add_subdirectory(reductions) - add_subdirectory(profiling) add_subdirectory(sunmemory) + if(SUNDIALS_BUILD_WITH_PROFILING) + add_subdirectory(profiling) + endif() endif() From 3c60571a034e29a0df379f73b4dc79b0c1e6accd Mon Sep 17 00:00:00 2001 From: Cody Balos Date: Fri, 27 Oct 2023 14:21:08 -0700 Subject: [PATCH 21/36] fix windows includes and resolution --- src/sundials/sundials_profiler.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index 4cf2141881..e12ea2deb2 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -30,9 +30,7 @@ #elif !(defined(WIN32) || defined(_WIN32)) #error POSIX is needed for clock_getttime #else -#include #include -#include #endif #include @@ -42,7 +40,6 @@ #include "sundials_debug.h" #include "sundials_hashmap.h" -// #include "sundials_utils.h" #define SUNDIALS_ROOT_TIMER ((const char*)"From profiler epoch") @@ -314,7 +311,6 @@ int SUNProfiler_GetTimerResolution(SUNProfiler p, double* resolution) #elif (defined(WIN32) || defined(_WIN32)) && \ !defined(SUNDIALS_HAVE_POSIX_TIMERS) static LARGE_INTEGER ticks_per_sec; - LARGE_INTEGER ticks; if (!ticks_per_sec.QuadPart) { @@ -322,7 +318,7 @@ int SUNProfiler_GetTimerResolution(SUNProfiler p, double* resolution) if (!ticks_per_sec.QuadPart) { return -1; } } - *resolution = SUN_RCONST(1.0) / ticks_per_sec.QuadPart; + *resolution = (double) ticks_per_sec.QuadPart; return (0); #else From a8b0a4db8d10337f38b03db639b347929095027e Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Fri, 27 Oct 2023 14:24:12 -0700 Subject: [PATCH 22/36] add new functions to docs --- doc/shared/sundials/Profiling.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/doc/shared/sundials/Profiling.rst b/doc/shared/sundials/Profiling.rst index 4f9e9357df..fe5796755c 100644 --- a/doc/shared/sundials/Profiling.rst +++ b/doc/shared/sundials/Profiling.rst @@ -149,6 +149,31 @@ are available. * Returns zero if successful, or non-zero if an error occurred +.. c:function:: int SUNProfiler_GetElapsedTime(SUNProfiler p, const char* name, double* time) + + Get the elapsed time for the timer "name". + + **Arguments:** + * ``p`` -- a ``SUNProfiler`` object + * ``name`` -- the name for the profiling region of interest + * ``time`` -- upon return, this will point to the elapsed time for the timer + + **Returns:** + * Returns zero if successful, or non-zero if an error occurred + + +.. c:function:: int SUNProfiler_GetTimerResolution(SUNProfiler p, double* resolution) + + Ends the timing of a region indicated by the ``name``. + + **Arguments:** + * ``p`` -- a ``SUNProfiler`` object + * ``resolution`` -- upon return, this will point to the resolution for the timer + + **Returns:** + * Returns zero if successful, or non-zero if an error occurred + + .. c:function:: int SUNProfiler_Print(SUNProfiler p, FILE* fp) Prints out a profiling summary. When constructed with an MPI comm the summary From ec66531c117eccf16c2a8da488b82e5b3e4b65d8 Mon Sep 17 00:00:00 2001 From: Cody Balos Date: Mon, 30 Oct 2023 11:13:42 -0700 Subject: [PATCH 23/36] Apply suggestions from code review Co-authored-by: David Gardner --- doc/shared/sundials/Profiling.rst | 8 +++--- src/sundials/sundials_profiler.c | 29 ++++++++------------ test/unit_tests/profiling/CMakeLists.txt | 2 +- test/unit_tests/profiling/test_profiling.cpp | 11 +------- 4 files changed, 17 insertions(+), 33 deletions(-) diff --git a/doc/shared/sundials/Profiling.rst b/doc/shared/sundials/Profiling.rst index fe5796755c..51d45d6ce0 100644 --- a/doc/shared/sundials/Profiling.rst +++ b/doc/shared/sundials/Profiling.rst @@ -151,12 +151,12 @@ are available. .. c:function:: int SUNProfiler_GetElapsedTime(SUNProfiler p, const char* name, double* time) - Get the elapsed time for the timer "name". + Get the elapsed time for the timer "name" in seconds. **Arguments:** * ``p`` -- a ``SUNProfiler`` object * ``name`` -- the name for the profiling region of interest - * ``time`` -- upon return, this will point to the elapsed time for the timer + * ``time`` -- upon return, the elapsed time for the timer **Returns:** * Returns zero if successful, or non-zero if an error occurred @@ -164,11 +164,11 @@ are available. .. c:function:: int SUNProfiler_GetTimerResolution(SUNProfiler p, double* resolution) - Ends the timing of a region indicated by the ``name``. + Get the timer resolution in seconds. **Arguments:** * ``p`` -- a ``SUNProfiler`` object - * ``resolution`` -- upon return, this will point to the resolution for the timer + * ``resolution`` -- upon return, the resolution for the timer **Returns:** * Returns zero if successful, or non-zero if an error occurred diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index e12ea2deb2..7c04eff003 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -27,10 +27,10 @@ #include #include #include -#elif !(defined(WIN32) || defined(_WIN32)) -#error POSIX is needed for clock_getttime -#else +#elif defined(WIN32) || defined(_WIN32) #include +#else +#error POSIX is needed for clock_getttime #endif #include @@ -43,14 +43,14 @@ #define SUNDIALS_ROOT_TIMER ((const char*)"From profiler epoch") -#if (defined(WIN32) || defined(_WIN32)) && !defined(SUNDIALS_HAVE_POSIX_TIMERS) +#if defined(SUNDIALS_HAVE_POSIX_TIMERS) +typedef struct timespec sunTimespec; +#else typedef struct _sunTimespec { long int tv_sec; long int tv_nsec; } sunTimespec; -#else -typedef struct timespec sunTimespec; #endif /* Private functions */ @@ -117,7 +117,7 @@ static void sunStopTiming(sunTimerStruct* entry) s_difference = entry->toc->tv_sec - entry->tic->tv_sec; ns_difference = entry->toc->tv_nsec - entry->tic->tv_nsec; - if (ns_difference < 0.0) + if (ns_difference < 0) { s_difference--; ns_difference = 1000000000 + entry->toc->tv_nsec - entry->tic->tv_nsec; @@ -308,8 +308,7 @@ int SUNProfiler_GetTimerResolution(SUNProfiler p, double* resolution) *resolution = 1e-9 * ((double)spec.tv_nsec); return (0); -#elif (defined(WIN32) || defined(_WIN32)) && \ - !defined(SUNDIALS_HAVE_POSIX_TIMERS) +#elif (defined(WIN32) || defined(_WIN32)) static LARGE_INTEGER ticks_per_sec; if (!ticks_per_sec.QuadPart) @@ -398,21 +397,15 @@ int SUNProfiler_Print(SUNProfiler p, FILE* fp) if (rank == 0) { -#if defined(SUNDIALS_HAVE_POSIX_TIMERS) - sunTimespec spec; -#endif + double resolution; /* Sort the timers in descending order */ if (SUNHashMap_Sort(p->map, &sorted, sunCompareTimes)) return (-1); -#if defined(SUNDIALS_HAVE_POSIX_TIMERS) - clock_getres(CLOCK_MONOTONIC, &spec); -#endif + SUNProfiler_GetTimerResolution(p, &resolution) fprintf(fp, "\n============================================================" "====================================================\n"); fprintf(fp, "SUNDIALS GIT VERSION: %s\n", SUNDIALS_GIT_VERSION); fprintf(fp, "SUNDIALS PROFILER: %s\n", p->title); -#if defined(SUNDIALS_HAVE_POSIX_TIMERS) - fprintf(fp, "TIMER RESOLUTION: %gs\n", 1e-9 * ((double)spec.tv_nsec)); -#endif + fprintf(fp, "TIMER RESOLUTION: %gs\n", resolution)); fprintf(fp, "%-40s\t %% time (inclusive) \t max/rank \t average/rank \t count \n", "RESULTS:"); fprintf(fp, "==============================================================" diff --git a/test/unit_tests/profiling/CMakeLists.txt b/test/unit_tests/profiling/CMakeLists.txt index c29a6f2afe..8c0ce56ea6 100644 --- a/test/unit_tests/profiling/CMakeLists.txt +++ b/test/unit_tests/profiling/CMakeLists.txt @@ -2,7 +2,7 @@ # Programmer(s): David J. Gardner @ LLNL # ------------------------------------------------------------------------------ # SUNDIALS Copyright Start -# Copyright (c) 2002-2022, Lawrence Livermore National Security +# Copyright (c) 2002-2023, Lawrence Livermore National Security # and Southern Methodist University. # All rights reserved. # diff --git a/test/unit_tests/profiling/test_profiling.cpp b/test/unit_tests/profiling/test_profiling.cpp index 45e59e655d..2fea55907f 100644 --- a/test/unit_tests/profiling/test_profiling.cpp +++ b/test/unit_tests/profiling/test_profiling.cpp @@ -2,7 +2,7 @@ * Programmer(s): David J. Gardner @ LLNL * ----------------------------------------------------------------------------- * SUNDIALS Copyright Start - * Copyright (c) 2002-2022, Lawrence Livermore National Security + * Copyright (c) 2002-2023, Lawrence Livermore National Security * and Southern Methodist University. * All rights reserved. * @@ -21,7 +21,6 @@ #include "sundials/sundials_math.h" #include "sundials/sundials_profiler.h" -#include "sundials/sundials_types.h" int sleep(SUNProfiler prof, int sec, double* chrono) { @@ -49,14 +48,6 @@ int print_timings(SUNProfiler prof) return 1; } - flag = SUNProfiler_Print(prof, stdout); - if (flag) - { - std::cerr << ">>> FAILURE: " - << "SUNProfiler_Print returned " << flag << "\n"; - return 1; - } - return 0; } From 69b7a219223b650454e94c2df0c301342d285f79 Mon Sep 17 00:00:00 2001 From: Cody Balos Date: Mon, 30 Oct 2023 11:32:42 -0700 Subject: [PATCH 24/36] simplify ifdef checks --- src/sundials/sundials_profiler.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/sundials/sundials_profiler.c b/src/sundials/sundials_profiler.c index 7c04eff003..adc2052c2d 100644 --- a/src/sundials/sundials_profiler.c +++ b/src/sundials/sundials_profiler.c @@ -30,7 +30,7 @@ #elif defined(WIN32) || defined(_WIN32) #include #else -#error POSIX is needed for clock_getttime +#error SUNProfiler needs POSIX or Windows timers #endif #include @@ -321,7 +321,7 @@ int SUNProfiler_GetTimerResolution(SUNProfiler p, double* resolution) return (0); #else - return (-1); +#error SUNProfiler needs POSIX or Windows timers #endif } @@ -400,12 +400,12 @@ int SUNProfiler_Print(SUNProfiler p, FILE* fp) double resolution; /* Sort the timers in descending order */ if (SUNHashMap_Sort(p->map, &sorted, sunCompareTimes)) return (-1); - SUNProfiler_GetTimerResolution(p, &resolution) + SUNProfiler_GetTimerResolution(p, &resolution); fprintf(fp, "\n============================================================" "====================================================\n"); fprintf(fp, "SUNDIALS GIT VERSION: %s\n", SUNDIALS_GIT_VERSION); fprintf(fp, "SUNDIALS PROFILER: %s\n", p->title); - fprintf(fp, "TIMER RESOLUTION: %gs\n", resolution)); + fprintf(fp, "TIMER RESOLUTION: %gs\n", resolution); fprintf(fp, "%-40s\t %% time (inclusive) \t max/rank \t average/rank \t count \n", "RESULTS:"); fprintf(fp, "==============================================================" @@ -558,7 +558,9 @@ int sunCompareTimes(const void* l, const void* r) int sunclock_gettime_monotonic(sunTimespec* ts) { -#if (defined(WIN32) || defined(_WIN32)) && !defined(SUNDIALS_HAVE_POSIX_TIMERS) +#if defined(SUNDIALS_HAVE_POSIX_TIMERS) + return clock_gettime(CLOCK_MONOTONIC, ts); +#elif (defined(WIN32) || defined(_WIN32)) static LARGE_INTEGER ticks_per_sec; LARGE_INTEGER ticks; @@ -577,7 +579,7 @@ int sunclock_gettime_monotonic(sunTimespec* ts) ticks_per_sec.QuadPart); return 0; -#else - return clock_gettime(CLOCK_MONOTONIC, ts); +#else +#error SUNProfiler needs POSIX or Windows timers #endif } From 99c338b2e73baf947c7214e751b7f2ba0947387b Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Mon, 30 Oct 2023 11:41:17 -0700 Subject: [PATCH 25/36] move C++ profiler parts to their own header file --- include/sundials/sundials_profiler.h | 34 ++--------------- include/sundials/sundials_profiler.hpp | 52 ++++++++++++++++++++++++++ scripts/shared | 1 + 3 files changed, 57 insertions(+), 30 deletions(-) create mode 100644 include/sundials/sundials_profiler.hpp diff --git a/include/sundials/sundials_profiler.h b/include/sundials/sundials_profiler.h index f793f31b36..c6461d0b78 100644 --- a/include/sundials/sundials_profiler.h +++ b/include/sundials/sundials_profiler.h @@ -54,10 +54,6 @@ SUNDIALS_EXPORT int SUNProfiler_Reset(SUNProfiler p); #define SUNDIALS_MARK_END(profobj, name) CALI_MARK_END(name) -#ifdef __cplusplus -#define SUNDIALS_CXX_MARK_FUNCTION(projobj) CALI_CXX_MARK_FUNCTION -#endif - #elif defined(SUNDIALS_BUILD_WITH_PROFILING) #define SUNDIALS_MARK_FUNCTION_BEGIN(profobj) \ @@ -74,11 +70,6 @@ SUNDIALS_EXPORT int SUNProfiler_Reset(SUNProfiler p); #define SUNDIALS_MARK_END(profobj, name) SUNProfiler_End(profobj, (name)) -#ifdef __cplusplus -#define SUNDIALS_CXX_MARK_FUNCTION(profobj) \ - sundials::ProfilerMarkScope __ProfilerMarkScope(profobj, __func__) -#endif - #else #define SUNDIALS_MARK_FUNCTION_BEGIN(profobj) @@ -100,26 +91,9 @@ SUNDIALS_EXPORT int SUNProfiler_Reset(SUNProfiler p); #ifdef __cplusplus } -namespace sundials { -/* Convenience class for C++ codes. - Allows for simpler profiler statements using C++ scoping rules. */ -class ProfilerMarkScope -{ -public: - ProfilerMarkScope(SUNProfiler prof, const char* name) - { - prof_ = prof; - name_ = name; - SUNProfiler_Begin(prof_, name_); - } - - ~ProfilerMarkScope() { SUNProfiler_End(prof_, name_); } - -private: - SUNProfiler prof_; - const char* name_; -}; -} // namespace sundials +/* We include this here for backwards compatibility + (the contents used to be defined here directly) */ +#include #endif -#endif /* SUNDIALS_PROFILER_H_ */ +#endif /* SUNDIALS_PROFILER_H */ diff --git a/include/sundials/sundials_profiler.hpp b/include/sundials/sundials_profiler.hpp new file mode 100644 index 0000000000..81bc95f920 --- /dev/null +++ b/include/sundials/sundials_profiler.hpp @@ -0,0 +1,52 @@ +/* ----------------------------------------------------------------- + * Programmer: Cody J. Balos @ LLNL + * ----------------------------------------------------------------- + * SUNDIALS Copyright Start + * Copyright (c) 2002-2023, Lawrence Livermore National Security + * and Southern Methodist University. + * All rights reserved. + * + * See the top-level LICENSE and NOTICE files for details. + * + * SPDX-License-Identifier: BSD-3-Clause + * SUNDIALS Copyright End + * -----------------------------------------------------------------*/ + +#ifndef _SUNDIALS_PROFILER_HPP +#define _SUNDIALS_PROFILER_HPP + +#include +#include +#include + +#if defined(SUNDIALS_BUILD_WITH_PROFILING) && defined(SUNDIALS_CALIPER_ENABLED) +#define SUNDIALS_CXX_MARK_FUNCTION(projobj) CALI_CXX_MARK_FUNCTION +#elif defined(SUNDIALS_BUILD_WITH_PROFILING) +#define SUNDIALS_CXX_MARK_FUNCTION(profobj) \ + sundials::ProfilerMarkScope __ProfilerMarkScope(profobj, __func__) +#else +#define SUNDIALS_CXX_MARK_FUNCTION(profobj) +#endif + +namespace sundials { +/* Convenience class for C++ codes. + Allows for simpler profiler statements using C++ scoping rules. */ +class ProfilerMarkScope +{ +public: + ProfilerMarkScope(SUNProfiler prof, const char* name) + { + prof_ = prof; + name_ = name; + SUNProfiler_Begin(prof_, name_); + } + + ~ProfilerMarkScope() { SUNProfiler_End(prof_, name_); } + +private: + SUNProfiler prof_; + const char* name_; +}; +} // namespace sundials + +#endif /* SUNDIALS_PROFILER_HPP */ diff --git a/scripts/shared b/scripts/shared index d159a4d5d7..1347175464 100755 --- a/scripts/shared +++ b/scripts/shared @@ -152,6 +152,7 @@ $tar $tarfile $distrobase/include/sundials/sundials_nonlinearsolver.hpp $tar $tarfile $distrobase/include/sundials/sundials_nvector_senswrapper.h $tar $tarfile $distrobase/include/sundials/sundials_nvector.h $tar $tarfile $distrobase/include/sundials/sundials_profiler.h +$tar $tarfile $distrobase/include/sundials/sundials_profiler.hpp $tar $tarfile $distrobase/include/sundials/sundials_sycl_policies.hpp $tar $tarfile $distrobase/include/sundials/sundials_types.h $tar $tarfile $distrobase/include/sundials/sundials_version.h From 5bfc36583fc0b20e01672ff5798713646fb4b1b5 Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Mon, 30 Oct 2023 11:45:25 -0700 Subject: [PATCH 26/36] add doc notes --- doc/shared/Install.rst | 1 + doc/shared/sundials/Profiling.rst | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/doc/shared/Install.rst b/doc/shared/Install.rst index f6126c9bb0..f132538739 100644 --- a/doc/shared/Install.rst +++ b/doc/shared/Install.rst @@ -1022,6 +1022,7 @@ illustration only. .. cmakeoption:: SUNDIALS_BUILD_WITH_PROFILING Build SUNDIALS with capabilties for fine-grained profiling. + This requires POSIX timers or the Windows ``profileapi.h`` timers. Default: OFF diff --git a/doc/shared/sundials/Profiling.rst b/doc/shared/sundials/Profiling.rst index 51d45d6ce0..a4d2d5de78 100644 --- a/doc/shared/sundials/Profiling.rst +++ b/doc/shared/sundials/Profiling.rst @@ -48,6 +48,11 @@ If Caliper is enabled, then users should refer to the `Caliper documentation Date: Mon, 30 Oct 2023 12:37:48 -0700 Subject: [PATCH 27/36] a few minor fixes --- doc/shared/sundials/Profiling.rst | 2 +- include/sundials/sundials_profiler.h | 4 ---- src/sundials/CMakeLists.txt | 1 + 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/doc/shared/sundials/Profiling.rst b/doc/shared/sundials/Profiling.rst index a4d2d5de78..4695643f29 100644 --- a/doc/shared/sundials/Profiling.rst +++ b/doc/shared/sundials/Profiling.rst @@ -51,7 +51,7 @@ setting the ``CALI_CONFIG`` environment variable. .. note:: - The SUNDIALS profilers requires POSIX timers or the Windows ``profileapi.h`` timers. + The SUNDIALS profiler requires POSIX timers or the Windows ``profileapi.h`` timers. .. warning:: diff --git a/include/sundials/sundials_profiler.h b/include/sundials/sundials_profiler.h index c6461d0b78..a7a1666736 100644 --- a/include/sundials/sundials_profiler.h +++ b/include/sundials/sundials_profiler.h @@ -82,10 +82,6 @@ SUNDIALS_EXPORT int SUNProfiler_Reset(SUNProfiler p); #define SUNDIALS_MARK_END(profobj, name) -#ifdef __cplusplus -#define SUNDIALS_CXX_MARK_FUNCTION(profobj) -#endif - #endif #ifdef __cplusplus diff --git a/src/sundials/CMakeLists.txt b/src/sundials/CMakeLists.txt index 16dd005cee..08afde2570 100644 --- a/src/sundials/CMakeLists.txt +++ b/src/sundials/CMakeLists.txt @@ -42,6 +42,7 @@ set(sundials_HEADERS sundials_nvector.h sundials_nvector.hpp sundials_profiler.h + sundials_profiler.hpp sundials_logger.h sundials_types.h sundials_version.h From 6713aea978ba904f6a257f747e9ce0c6c57685ac Mon Sep 17 00:00:00 2001 From: Cody Balos Date: Mon, 30 Oct 2023 14:12:39 -0700 Subject: [PATCH 28/36] include string header for stod/stoi --- .../CXX_serial/ark_test_analytic_sys_mri.cpp | 9 +++++---- .../CXX_serial/ark_test_dahlquist_mri.cpp | 17 +++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/test/unit_tests/arkode/CXX_serial/ark_test_analytic_sys_mri.cpp b/test/unit_tests/arkode/CXX_serial/ark_test_analytic_sys_mri.cpp index 4abd91c925..ce0b9bdd04 100644 --- a/test/unit_tests/arkode/CXX_serial/ark_test_analytic_sys_mri.cpp +++ b/test/unit_tests/arkode/CXX_serial/ark_test_analytic_sys_mri.cpp @@ -22,9 +22,10 @@ *-----------------------------------------------------------------*/ // Header files -#include +#include #include -#include +#include +#include #include #include #include @@ -99,8 +100,8 @@ int main(int argc, char* argv[]) // if an argument supplied, set fixedpoint (otherwise use SUNFALSE) fixedpoint = SUNFALSE; - if (argc > 1) fixedpoint = stoi(argv[1], NULL); - if (argc > 2) Nt = stoi(argv[2], NULL); + if (argc > 1) fixedpoint = std::stoi(argv[1], NULL); + if (argc > 2) Nt = std::stoi(argv[2], NULL); // Initial problem output cout << "\nAnalytical ODE test problem:\n"; diff --git a/test/unit_tests/arkode/CXX_serial/ark_test_dahlquist_mri.cpp b/test/unit_tests/arkode/CXX_serial/ark_test_dahlquist_mri.cpp index 7f52a88d86..ffb23ec7c1 100644 --- a/test/unit_tests/arkode/CXX_serial/ark_test_dahlquist_mri.cpp +++ b/test/unit_tests/arkode/CXX_serial/ark_test_dahlquist_mri.cpp @@ -17,10 +17,11 @@ * ---------------------------------------------------------------------------*/ // Header files -#include +#include #include -#include +#include #include +#include #include #include @@ -91,12 +92,12 @@ int main(int argc, char* argv[]) UserData udata; // Check for inputs - if (argc > 1) udata.lambda_e = stod(argv[1]); - if (argc > 2) udata.lambda_i = stod(argv[2]); - if (argc > 3) udata.lambda_f = stod(argv[3]); - if (argc > 4) hs = stod(argv[4]); - if (argc > 5) hf = stod(argv[5]); - if (argc > 5) nsteps = stoi(argv[6]); + if (argc > 1) udata.lambda_e = std::stod(argv[1]); + if (argc > 2) udata.lambda_i = std::stod(argv[2]); + if (argc > 3) udata.lambda_f = std::stod(argv[3]); + if (argc > 4) hs = std::stod(argv[4]); + if (argc > 5) hf = std::stod(argv[5]); + if (argc > 5) nsteps = std::stoi(argv[6]); // Output problem setup cout << "\nDahlquist ODE test problem:\n"; From caeda656d41de7e00fc7a108a556408f5076876f Mon Sep 17 00:00:00 2001 From: Cody Balos Date: Mon, 30 Oct 2023 14:14:20 -0700 Subject: [PATCH 29/36] Enable unit tests to build on Windows when access to private functions is required --- test/unit_tests/arkode/CXX_serial/CMakeLists.txt | 13 ++++++++++--- test/unit_tests/arkode/C_serial/CMakeLists.txt | 12 +++++++++--- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/test/unit_tests/arkode/CXX_serial/CMakeLists.txt b/test/unit_tests/arkode/CXX_serial/CMakeLists.txt index 84d040ad24..de29e53937 100644 --- a/test/unit_tests/arkode/CXX_serial/CMakeLists.txt +++ b/test/unit_tests/arkode/CXX_serial/CMakeLists.txt @@ -50,10 +50,17 @@ foreach(test_tuple ${unit_tests}) ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/src) - # Libraries to link against + # We explicitly choose which object libraries to link to + # and link in the arkode objects so that we have access to + # private functions w/o changing their visibility in the installed libraries. target_link_libraries(${test_target} - sundials_arkode - sundials_nvecserial + $ + sundials_sunmemsys_obj + sundials_nvecserial_obj + sundials_sunlinsolband_obj + sundials_sunlinsoldense_obj + sundials_sunnonlinsolnewton_obj + sundials_sunnonlinsolfixedpoint_obj ${EXE_EXTRA_LINK_LIBS}) endif() diff --git a/test/unit_tests/arkode/C_serial/CMakeLists.txt b/test/unit_tests/arkode/C_serial/CMakeLists.txt index 2c4daa7d74..7502d3b341 100644 --- a/test/unit_tests/arkode/C_serial/CMakeLists.txt +++ b/test/unit_tests/arkode/C_serial/CMakeLists.txt @@ -55,10 +55,16 @@ foreach(test_tuple ${ARKODE_unit_tests}) ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/src) - # libraries to link against + # We explicitly choose which object libraries to link to + # and link in the arkode objects so that we have access to + # private functions w/o changing their visibility in the installed libraries. target_link_libraries(${test} - sundials_arkode - sundials_nvecserial + $ + sundials_sunmemsys_obj + sundials_nvecserial_obj + sundials_sunlinsolband_obj + sundials_sunlinsoldense_obj + sundials_sunnonlinsolnewton_obj ${EXE_EXTRA_LINK_LIBS}) endif() From 7aa0e52e9977df2c6108cbd590146b4fd95afffe Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Mon, 30 Oct 2023 14:22:59 -0700 Subject: [PATCH 30/36] use integer 1e9 --- test/unit_tests/profiling/test_profiling.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit_tests/profiling/test_profiling.cpp b/test/unit_tests/profiling/test_profiling.cpp index 2fea55907f..efbf238818 100644 --- a/test/unit_tests/profiling/test_profiling.cpp +++ b/test/unit_tests/profiling/test_profiling.cpp @@ -33,7 +33,7 @@ int sleep(SUNProfiler prof, int sec, double* chrono) std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); *chrono = std::chrono::duration_cast(end - begin).count() * - 1e-9; + 1000000000; return 0; } From 9d6de5b0b19a3d4b37951514e3ab9d864d2b353f Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Mon, 30 Oct 2023 14:57:00 -0700 Subject: [PATCH 31/36] workaround for cmake 3.12 --- test/unit_tests/arkode/CXX_serial/CMakeLists.txt | 10 +++++++--- test/unit_tests/arkode/C_serial/CMakeLists.txt | 10 +++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/test/unit_tests/arkode/CXX_serial/CMakeLists.txt b/test/unit_tests/arkode/CXX_serial/CMakeLists.txt index de29e53937..8d66eff9a4 100644 --- a/test/unit_tests/arkode/CXX_serial/CMakeLists.txt +++ b/test/unit_tests/arkode/CXX_serial/CMakeLists.txt @@ -50,9 +50,9 @@ foreach(test_tuple ${unit_tests}) ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/src) - # We explicitly choose which object libraries to link to - # and link in the arkode objects so that we have access to - # private functions w/o changing their visibility in the installed libraries. + # We explicitly choose which object libraries to link to and link in the + # arkode objects so that we have access to private functions w/o changing + # their visibility in the installed libraries. target_link_libraries(${test_target} $ sundials_sunmemsys_obj @@ -63,6 +63,10 @@ foreach(test_tuple ${unit_tests}) sundials_sunnonlinsolfixedpoint_obj ${EXE_EXTRA_LINK_LIBS}) + # Tell CMake that we depend on the ARKODE library since it does not pick + # that up from $. + add_dependencies(${test} sundials_arkode_obj) + endif() # Check if test args are provided and set the test name diff --git a/test/unit_tests/arkode/C_serial/CMakeLists.txt b/test/unit_tests/arkode/C_serial/CMakeLists.txt index 7502d3b341..bddff54d88 100644 --- a/test/unit_tests/arkode/C_serial/CMakeLists.txt +++ b/test/unit_tests/arkode/C_serial/CMakeLists.txt @@ -55,9 +55,9 @@ foreach(test_tuple ${ARKODE_unit_tests}) ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/src) - # We explicitly choose which object libraries to link to - # and link in the arkode objects so that we have access to - # private functions w/o changing their visibility in the installed libraries. + # We explicitly choose which object libraries to link to and link in the + # arkode objects so that we have access to private functions w/o changing + # their visibility in the installed libraries. target_link_libraries(${test} $ sundials_sunmemsys_obj @@ -67,6 +67,10 @@ foreach(test_tuple ${ARKODE_unit_tests}) sundials_sunnonlinsolnewton_obj ${EXE_EXTRA_LINK_LIBS}) + # Tell CMake that we depend on the ARKODE library since it does not pick + # that up from $. + add_dependencies(${test} sundials_arkode_obj) + endif() # check if test args are provided and set the test name From be907b3638ea6522ae12d9eb86757a09ef6efdbf Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Mon, 30 Oct 2023 15:54:10 -0700 Subject: [PATCH 32/36] typo --- test/unit_tests/arkode/CXX_serial/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit_tests/arkode/CXX_serial/CMakeLists.txt b/test/unit_tests/arkode/CXX_serial/CMakeLists.txt index 8d66eff9a4..b0ea386c44 100644 --- a/test/unit_tests/arkode/CXX_serial/CMakeLists.txt +++ b/test/unit_tests/arkode/CXX_serial/CMakeLists.txt @@ -65,7 +65,7 @@ foreach(test_tuple ${unit_tests}) # Tell CMake that we depend on the ARKODE library since it does not pick # that up from $. - add_dependencies(${test} sundials_arkode_obj) + add_dependencies(${test_target} sundials_arkode_obj) endif() From 0a53d7662231d6c3b3c4ac08c91dac8200a51b4f Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Mon, 30 Oct 2023 16:32:20 -0700 Subject: [PATCH 33/36] add slack for timing test --- test/unit_tests/profiling/test_profiling.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/unit_tests/profiling/test_profiling.cpp b/test/unit_tests/profiling/test_profiling.cpp index efbf238818..b8cdc7bfd3 100644 --- a/test/unit_tests/profiling/test_profiling.cpp +++ b/test/unit_tests/profiling/test_profiling.cpp @@ -24,16 +24,15 @@ int sleep(SUNProfiler prof, int sec, double* chrono) { - std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); + auto begin = std::chrono::steady_clock::now(); int flag = SUNProfiler_Begin(prof, "sleep"); if (flag) return flag; std::this_thread::sleep_for(std::chrono::seconds(sec)); flag = SUNProfiler_End(prof, "sleep"); if (flag) return flag; - std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); - *chrono = - std::chrono::duration_cast(end - begin).count() * - 1000000000; + auto end = std::chrono::steady_clock::now(); + auto elapsed = std::chrono::duration_cast(end - begin).count(); + *chrono = std::chrono::duration(elapsed).count() * 1e-9; return 0; } @@ -109,7 +108,9 @@ int main() return 1; } - if (SUNRCompareTol(time, chrono, 10*resolution)) + // We use 100*resolution to allow for (a) some inaccuracy in the reported + // resolution and (b) the resolution of chrono itself. + if (SUNRCompareTol(time, chrono, 100*resolution)) { std::cerr << ">>> FAILURE: " << "time recorded was " << time << "s, but expected " << chrono From 55fd98de67c395a9bb1cefa91d2b70210e11b396 Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Tue, 31 Oct 2023 23:03:36 -0700 Subject: [PATCH 34/36] update tolerance --- test/unit_tests/profiling/test_profiling.cpp | 33 +++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/test/unit_tests/profiling/test_profiling.cpp b/test/unit_tests/profiling/test_profiling.cpp index b8cdc7bfd3..d8590fabb2 100644 --- a/test/unit_tests/profiling/test_profiling.cpp +++ b/test/unit_tests/profiling/test_profiling.cpp @@ -25,14 +25,20 @@ int sleep(SUNProfiler prof, int sec, double* chrono) { auto begin = std::chrono::steady_clock::now(); - int flag = SUNProfiler_Begin(prof, "sleep"); - if (flag) return flag; + + // We dont check the flag returned to avoid introducing extra + // overhead which makes it harder to compare the SUNProfiler + // time with the chrono time. + SUNProfiler_Begin(prof, "sleep"); std::this_thread::sleep_for(std::chrono::seconds(sec)); - flag = SUNProfiler_End(prof, "sleep"); - if (flag) return flag; + SUNProfiler_End(prof, "sleep"); + auto end = std::chrono::steady_clock::now(); - auto elapsed = std::chrono::duration_cast(end - begin).count(); + + auto elapsed = + std::chrono::duration_cast(end - begin).count(); *chrono = std::chrono::duration(elapsed).count() * 1e-9; + return 0; } @@ -91,8 +97,9 @@ int main() return 1; } - double time, resolution; - flag = SUNProfiler_GetElapsedTime(prof, "sleep", &time); + double time = 0; + double resolution = 0; + flag = SUNProfiler_GetElapsedTime(prof, "sleep", &time); if (flag) { std::cerr << ">>> FAILURE: " @@ -110,11 +117,11 @@ int main() // We use 100*resolution to allow for (a) some inaccuracy in the reported // resolution and (b) the resolution of chrono itself. - if (SUNRCompareTol(time, chrono, 100*resolution)) + if (SUNRCompareTol(time, chrono, 100 * resolution)) { std::cerr << ">>> FAILURE: " << "time recorded was " << time << "s, but expected " << chrono - << " +/- " << resolution << "\n"; + << "s +/- " << 100 * resolution << "\n"; return 1; } @@ -165,11 +172,13 @@ int main() return 1; } - if (SUNRCompareTol(time, chrono, 10*resolution)) + // We use 100*resolution to allow for (a) some inaccuracy in the reported + // resolution and (b) the resolution of chrono itself. + if (SUNRCompareTol(time, chrono, 100 * resolution)) { std::cerr << ">>> FAILURE: " << "time recorded was " << time << "s, but expected " << chrono - << " +/- " << resolution << "\n"; + << "s +/- " << 100 * resolution << "\n"; return 1; } @@ -180,7 +189,7 @@ int main() std::cout << "\nTest 3: multiple outputs to a file for plot test\n"; std::FILE* fout = std::fopen("profiling_test_output.txt", "w"); - if (!fout) + if (fout == nullptr) { std::cerr << ">>> FAILURE: " << "fopen returned a null pointer\n"; From 2bc100c09e0c9e2c8fe8c362435ea17d9acb701c Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Tue, 31 Oct 2023 23:04:05 -0700 Subject: [PATCH 35/36] turn off unit tests on mingw --- .github/workflows/windows-latest-mingw.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/windows-latest-mingw.yml b/.github/workflows/windows-latest-mingw.yml index 6a77075105..ab20ea721a 100644 --- a/.github/workflows/windows-latest-mingw.yml +++ b/.github/workflows/windows-latest-mingw.yml @@ -21,7 +21,7 @@ jobs: - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: cmake -G "MinGW Makefiles" -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DSUNDIALS_BUILD_WITH_PROFILING=ON -DSUNDIALS_LOGGING_LEVEL=2 -DSUNDIALS_TEST_UNITTESTS=ON -DEXAMPLES_ENABLE_CXX=ON + run: cmake -G "MinGW Makefiles" -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DSUNDIALS_BUILD_WITH_PROFILING=ON -DSUNDIALS_LOGGING_LEVEL=2 -DSUNDIALS_TEST_UNITTESTS=OFF -DEXAMPLES_ENABLE_CXX=ON - name: Build # Build your program with the given configuration From fe77dc9ec8ff3e6c8382e56973a2fa7185d60943 Mon Sep 17 00:00:00 2001 From: "Balos, Cody, J" Date: Wed, 1 Nov 2023 09:05:00 -0700 Subject: [PATCH 36/36] loosen test tolerance --- test/unit_tests/profiling/test_profiling.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/test/unit_tests/profiling/test_profiling.cpp b/test/unit_tests/profiling/test_profiling.cpp index d8590fabb2..7228fd7c9c 100644 --- a/test/unit_tests/profiling/test_profiling.cpp +++ b/test/unit_tests/profiling/test_profiling.cpp @@ -115,13 +115,11 @@ int main() return 1; } - // We use 100*resolution to allow for (a) some inaccuracy in the reported - // resolution and (b) the resolution of chrono itself. - if (SUNRCompareTol(time, chrono, 100 * resolution)) + if (SUNRCompareTol(time, chrono, 1e-2)) { std::cerr << ">>> FAILURE: " << "time recorded was " << time << "s, but expected " << chrono - << "s +/- " << 100 * resolution << "\n"; + << "s +/- " << 1e-2 << "\n"; return 1; } @@ -172,13 +170,11 @@ int main() return 1; } - // We use 100*resolution to allow for (a) some inaccuracy in the reported - // resolution and (b) the resolution of chrono itself. - if (SUNRCompareTol(time, chrono, 100 * resolution)) + if (SUNRCompareTol(time, chrono, 1e-2)) { std::cerr << ">>> FAILURE: " << "time recorded was " << time << "s, but expected " << chrono - << "s +/- " << 100 * resolution << "\n"; + << "s +/- " << 1e-2 << "\n"; return 1; }