diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2350faa10..ebe774e17 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -49,6 +49,19 @@ option(IPPL_USE_ALTERNATIVE_VARIANT
option(IPPL_USE_STANDARD_FOLDERS "Put all generated binaries in bin/lib folders" OFF)
option(IPPL_SKIP_FAILING_TESTS "Do not build/test tests that are currently marked as failing" OFF)
option(IPPL_ENABLE_SCRIPTS "Generate job script templates for some benchmarks/tests" OFF)
+option(IPPL_GPU_AWARE_MPI "Allow MPI to/from from device memory buffers" OFF)
+# logging options
+set(IPPL_LOG_LEVEL "off" CACHE STRING "Enable logging for messages of >=level")
+set_property(
+ CACHE IPPL_LOG_LEVEL
+ PROPERTY STRINGS
+ off
+ trace
+ debug
+ info
+ warn
+ error
+ critical)
# "Build IPPL as a shared library (ON) or static library (OFF)" OFF) if(IPPL_DYL)
# set(BUILD_SHARED_LIBS ON CACHE BOOL "" FORCE) message(WARNING "IPPL_DYL is deprecated; use
@@ -97,21 +110,6 @@ if(DEFINED USE_ALTERNATIVE_VARIANT)
set(IPPL_USE_ALTERNATIVE_VARIANT ${USE_ALTERNATIVE_VARIANT} CACHE BOOL "" FORCE)
endif()
-# ------------------------------------------------------------------------------
-# Debug: This tells the compiler to replace occurrences of ${
} with in debug info and error
-# messages.
-# ------------------------------------------------------------------------------
-add_compile_options(
- $<$:-ffile-prefix-map=${CMAKE_SOURCE_DIR}=.>
- $<$:-ffile-prefix-map=${CMAKE_SOURCE_DIR}=.>)
-
-if(DEFINED FETCHCONTENT_BASE_DIR)
- add_compile_options(
- $<$:-ffile-prefix-map=${FETCHCONTENT_BASE_DIR}=.3p>
- $<$:-ffile-prefix-map=${FETCHCONTENT_BASE_DIR}=.3p>
- )
-endif()
-
# ------------------------------------------------------------------------------
# Define sources for project
# ------------------------------------------------------------------------------
diff --git a/alpine/LandauDamping.cpp b/alpine/LandauDamping.cpp
index 90007b142..88808835d 100644
--- a/alpine/LandauDamping.cpp
+++ b/alpine/LandauDamping.cpp
@@ -37,17 +37,22 @@ const char* TestName = "LandauDamping";
#include "Manager/datatypes.h"
#include "Utility/IpplTimings.h"
+#include "Utility/Logging.h"
#include "LandauDampingManager.h"
#include "Manager/PicManager.h"
int main(int argc, char* argv[]) {
+#if defined(SPDLOG_ACTIVE_LEVEL) && (SPDLOG_ACTIVE_LEVEL != SPDLOG_LEVEL_OFF)
+ spdlog::set_pattern("[%^%-8l%$]%t| %v");
+ spdlog::set_level(spdlog::level::trace);
+#endif
ippl::initialize(argc, argv);
{
Inform msg(TestName);
Inform msg2all(TestName, INFORM_ALL_NODES);
- static IpplTimings::TimerRef mainTimer = IpplTimings::getTimer("total");
+ static IpplTimings::TimerRef mainTimer = IpplTimings::getTimer("total");
static IpplTimings::TimerRef initializeTimer = IpplTimings::getTimer("initialize");
IpplTimings::startTimer(mainTimer);
IpplTimings::startTimer(initializeTimer);
@@ -82,7 +87,7 @@ int main(int argc, char* argv[]) {
manager.pre_run();
IpplTimings::stopTimer(initializeTimer);
-
+
manager.setTime(0.0);
msg << "Starting iterations ..." << endl;
diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake
index 70bb39314..704d87a8b 100644
--- a/cmake/Dependencies.cmake
+++ b/cmake/Dependencies.cmake
@@ -44,6 +44,23 @@ if("OPENMP" IN_LIST IPPL_PLATFORMS)
colour_message(STATUS ${Green} "✅ OpenMP platform requested OpenMP found ${OPENMP_VERSION}")
endif()
+# ------------------------------------------------------------------------------
+# spdlog logging library
+# ------------------------------------------------------------------------------
+string(TOUPPER ${IPPL_LOG_LEVEL} IPPL_LOG_LEVEL_UPPERCASE)
+if(NOT "${IPPL_LOG_LEVEL_UPPERCASE}" MATCHES "OFF")
+ find_package(spdlog REQUIRED)
+ colour_message(STATUS ${Green} "✅ spdlog found ${spdlog_VERSION}")
+endif()
+
+# ------------------------------------------------------------------------------
+# fmt library (for formatting nice log messages)
+# ------------------------------------------------------------------------------
+if(NOT "${IPPL_LOG_LEVEL_UPPERCASE}" MATCHES "OFF")
+ find_package(fmt REQUIRED)
+ colour_message(STATUS ${Green} "✅ fmt found ${fmt_VERSION}")
+endif()
+
# ------------------------------------------------------------------------------
# Utility function to clear a list of vars one by one
# ------------------------------------------------------------------------------
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
index 4731c2f76..cad844a9d 100644
--- a/scripts/CMakeLists.txt
+++ b/scripts/CMakeLists.txt
@@ -9,6 +9,20 @@ message(STATUS "IPPL_MACHINENAME for script generation is: ${IPPL_MACHINENAME}")
# ------------------------------------------------------------------------------
set(IPPL_JOB_SUBMISSION_ACCOUNT "c41" CACHE STRING "Account to use for job submission templates")
+# populate IPPL_SCRIPTS_UENV from environment variable UENV_MOUNT_LIST (if present)
+if(DEFINED ENV{UENV_MOUNT_LIST})
+ set(IPPL_SCRIPTS_UENV "$ENV{UENV_MOUNT_LIST}"
+ CACHE STRING "UENV to use on alps when running scripts mount")
+ set(IPPL_SCRIPTS_UENV_VIEW "default" CACHE STRING "View to set in uenv")
+ colour_message(STATUS ${LightBlue}
+ "IPPL_SCRIPTS_UENV set from UENV_MOUNT_LIST: ${IPPL_SCRIPTS_UENV}")
+else()
+ # Remove any cached and normal definitions so the variable is completely unset
+ unset(IPPL_SCRIPTS_UENV CACHE)
+ unset(IPPL_SCRIPTS_UENV_VIEW CACHE)
+ colour_message(STATUS ${LightBlue} "No UENV detected")
+endif()
+
# ------------------------------------------------------------------------------
# utility function to get target path/name since we can't use generator expressions to set variables
# directly
diff --git a/scripts/landau/strong-scaling-alps/jobscript-gh200.slurm b/scripts/landau/strong-scaling-alps/jobscript-gh200.slurm
index 4c40a5bc2..14542f1f3 100644
--- a/scripts/landau/strong-scaling-alps/jobscript-gh200.slurm
+++ b/scripts/landau/strong-scaling-alps/jobscript-gh200.slurm
@@ -12,8 +12,8 @@
#SBATCH --cpus-per-task=72
#SBATCH --exclusive
-#SBATCH --uenv=/capstor/store/cscs/cscs/public/uenvs/opal-x-gh200-mpich-gcc-2025-09-28.squashfs
-#SBATCH --view=develop
+#SBATCH --uenv=@IPPL_SCRIPTS_UENV@
+#SBATCH --view=@IPPL_SCRIPTS_UENV_VIEW@
#SBATCH --output=landau__n_.out
#SBATCH --error=landau__n_.error
diff --git a/scripts/landau/strong-scaling-alps/jobscript-mi300.slurm b/scripts/landau/strong-scaling-alps/jobscript-mi300.slurm
index de29cc9dc..1bd459192 100644
--- a/scripts/landau/strong-scaling-alps/jobscript-mi300.slurm
+++ b/scripts/landau/strong-scaling-alps/jobscript-mi300.slurm
@@ -13,8 +13,8 @@
#SBATCH --cpus-per-task=48
#SBATCH --exclusive
-#SBATCH --uenv=/capstor/scratch/cscs/biddisco/opal-x-mi300-mpich-gcc-2025-10-27.squashfs
-#SBATCH --view=default
+#SBATCH --uenv=@IPPL_SCRIPTS_UENV@
+#SBATCH --view=@IPPL_SCRIPTS_UENV_VIEW@
#SBATCH --output=landau__n_.out
#SBATCH --error=landau__n_.error
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index c4778b174..51cfb879b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -35,6 +35,14 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/IpplVersions.h.in
add_library(ippl)
+if(NOT "${IPPL_LOG_LEVEL_UPPERCASE}" MATCHES "OFF")
+ target_compile_definitions(ippl PUBLIC IPPL_LOGGING_ENABLED=1)
+ target_compile_definitions(ippl
+ PUBLIC SPDLOG_ACTIVE_LEVEL=SPDLOG_LEVEL_${IPPL_LOG_LEVEL_UPPERCASE})
+ target_link_libraries(ippl PUBLIC spdlog::spdlog $<$:ws2_32>)
+ target_link_libraries(ippl PUBLIC fmt::fmt)
+endif()
+
target_compile_features(ippl PUBLIC cxx_std_20)
target_compile_options(
diff --git a/src/Communicate/Archive.h b/src/Communicate/Archive.h
index 6ec74f946..ca897ca96 100644
--- a/src/Communicate/Archive.h
+++ b/src/Communicate/Archive.h
@@ -16,19 +16,20 @@
#include "Types/ViewTypes.h"
#include "Types/Vector.h"
+#undef IPPL_SIMPLE_VIEW_STORAGE
namespace ippl {
namespace detail {
/*!
* @file Archive.h
- * Serialize and desesrialize particle attributes.
+ * Serialize and deserialize particle attributes.
* @tparam Properties variadic template for Kokkos::View
*/
- template
+ template
class Archive {
public:
- using buffer_type = typename ViewType::view_type;
+ using buffer_type = BufferType;
using pointer_type = typename buffer_type::pointer_type;
Archive(size_type size = 0);
@@ -73,7 +74,7 @@ namespace ippl {
/*!
* @returns a pointer to the data of the buffer
*/
- pointer_type getBuffer() { return buffer_m.data(); }
+ pointer_type getData() { return buffer_m.data(); }
/*!
* @returns the size of the buffer
@@ -82,10 +83,18 @@ namespace ippl {
size_type getBufferSize() const { return buffer_m.size(); }
- void resizeBuffer(size_type size) { Kokkos::resize(buffer_m, size); }
-
- void reallocBuffer(size_type size) { Kokkos::realloc(buffer_m, size); }
+ void reallocBuffer(size_type size) {
+#ifdef IPPL_SIMPLE_VIEW_STORAGE
+ Kokkos::realloc(buffer_m, size);
+#else
+ buffer_m.reallocBuffer(size);
+#endif
+ }
+ void resetReadWritePos() {
+ readpos_m = 0;
+ writepos_m = 0;
+ }
void resetWritePos() { writepos_m = 0; }
void resetReadPos() { readpos_m = 0; }
@@ -97,7 +106,7 @@ namespace ippl {
//! read position for deserialization
size_type readpos_m;
//! serialized data
- buffer_type buffer_m;
+ BufferType buffer_m;
};
} // namespace detail
} // namespace ippl
diff --git a/src/Communicate/Archive.hpp b/src/Communicate/Archive.hpp
index f1d097a69..1135c8157 100644
--- a/src/Communicate/Archive.hpp
+++ b/src/Communicate/Archive.hpp
@@ -4,99 +4,116 @@
//
#include
+#include "Utility/Logging.h"
+
#include "Archive.h"
namespace ippl {
namespace detail {
- template
- Archive::Archive(size_type size)
+ template
+ Archive::Archive(size_type size)
: writepos_m(0)
, readpos_m(0)
, buffer_m("buffer", size) {}
- template
+ // -----------------------------------
+ // Scalar serialize
+ template
template
- void Archive::serialize(const Kokkos::View& view,
- size_type nsends) {
- using exec_space = typename Kokkos::View::execution_space;
- using policy_type = Kokkos::RangePolicy;
-
- size_t size = sizeof(T);
- Kokkos::parallel_for(
- "Archive::serialize()", policy_type(0, nsends),
- KOKKOS_CLASS_LAMBDA(const size_type i) {
- std::memcpy(buffer_m.data() + i * size + writepos_m, view.data() + i, size);
- });
+ void Archive::serialize(const Kokkos::View& view,
+ size_type nsends) {
+ constexpr size_t size = sizeof(T);
+ char* dst_ptr = (char*)(buffer_m.data()) + writepos_m;
+ char* src_ptr = (char*)(view.data());
+ assert(writepos_m + (nsends * size) <= buffer_m.size());
+ // construct temp views of the src/dst buffers of the correct size (bytes)
+ Kokkos::View src_view(src_ptr, size * nsends);
+ Kokkos::View dst_view(dst_ptr, size * nsends);
+ Kokkos::deep_copy(dst_view, src_view);
Kokkos::fence();
- writepos_m += size * nsends;
+ SPDLOG_TRACE("Incrementing writepos: {}, from {}, to {}", (void*)dst_view.data(),
+ writepos_m, writepos_m + (nsends * size));
+ writepos_m += (nsends * size);
}
- template
+ // -----------------------------------
+ // Vector serialize
+ template
template
- void Archive::serialize(
- const Kokkos::View*, ViewArgs...>& view, size_type nsends) {
- using exec_space = typename Kokkos::View::execution_space;
-
- size_t size = sizeof(T);
- // Default index type for range policies is int64,
+ void Archive::serialize(const Kokkos::View*, ViewArgs...>& view,
+ size_type nsends) {
+ constexpr size_t size = sizeof(T);
+ char* dst_ptr = (char*)(buffer_m.data());
+ ippl::Vector* src_ptr = view.data();
+ auto wp = writepos_m;
+ // The Kokkos range policies expect int64
// so we have to explicitly specify size_type (uint64)
+ using exec_space = typename Kokkos::View::execution_space;
using mdrange_t =
Kokkos::MDRangePolicy, Kokkos::IndexType, exec_space>;
Kokkos::parallel_for(
- "Archive::serialize()",
- // The constructor for Kokkos range policies always
- // expects int64 regardless of index type provided
- // by template parameters, so the typecast is necessary
- // to avoid compiler warnings
- mdrange_t({0, 0}, {(long int)nsends, Dim}),
- KOKKOS_CLASS_LAMBDA(const size_type i, const size_t d) {
- std::memcpy(buffer_m.data() + (Dim * i + d) * size + writepos_m,
- &(*(view.data() + i))[d], size);
+ "Archive::serialize()", mdrange_t({0, 0}, {(long int)nsends, Dim}),
+ KOKKOS_LAMBDA(const size_type i, const size_t d) {
+ std::memcpy(dst_ptr + (Dim * i + d) * size + wp, &(*(src_ptr + i))[d], size);
});
+
Kokkos::fence();
writepos_m += Dim * size * nsends;
}
- template
+ // -----------------------------------
+ // Scalar Deserialize
+ template
template
- void Archive::deserialize(Kokkos::View& view,
- size_type nrecvs) {
- using exec_space = typename Kokkos::View::execution_space;
- using policy_type = Kokkos::RangePolicy;
-
- size_t size = sizeof(T);
+ void Archive::deserialize(Kokkos::View& view,
+ size_type nrecvs) {
+ // if we have to enlarge the destination view
if (nrecvs > view.extent(0)) {
+ SPDLOG_WARN("DeSerialization realloc: {}, from {}, to {}", (void*)view.data(),
+ view.extent(0), nrecvs);
Kokkos::realloc(view, nrecvs);
}
- Kokkos::parallel_for(
- "Archive::deserialize()", policy_type(0, nrecvs),
- KOKKOS_CLASS_LAMBDA(const size_type i) {
- std::memcpy(view.data() + i, buffer_m.data() + i * size + readpos_m, size);
- });
- // Wait for deserialization kernel to complete
- // (as with serialization kernels)
+ //
+ constexpr size_t size = sizeof(T);
+ char* src_ptr = (char*)(buffer_m.data()) + readpos_m;
+ char* dst_ptr = (char*)(view.data());
+ assert(readpos_m + (nrecvs * size) <= buffer_m.size());
+ // construct temp views of the src/dst buffers of the correct size (bytes)
+ Kokkos::View src_view(src_ptr, size * nrecvs);
+ Kokkos::View dst_view(dst_ptr, size * nrecvs);
+ Kokkos::deep_copy(dst_view, src_view);
Kokkos::fence();
- readpos_m += size * nrecvs;
+ SPDLOG_TRACE("Incrementing readpos: {}, from {}, to {}", (void*)buffer_m.data(),
+ readpos_m, readpos_m + (nrecvs * size));
+ readpos_m += (nrecvs * size);
}
- template
+ // -----------------------------------
+ // Vecto Deserialize
+ template
template
- void Archive::deserialize(Kokkos::View*, ViewArgs...>& view,
- size_type nrecvs) {
- using exec_space = typename Kokkos::View::execution_space;
-
- size_t size = sizeof(T);
+ void Archive::deserialize(Kokkos::View*, ViewArgs...>& view,
+ size_type nrecvs) //
+ {
+ // if we have to enlarge the destination view
if (nrecvs > view.extent(0)) {
+ SPDLOG_WARN("DeSerialization realloc: {}, from {}, to {}", (void*)view.data(),
+ view.extent(0), nrecvs);
Kokkos::realloc(view, nrecvs);
}
+ //
+ constexpr size_t size = sizeof(T);
+ char* src_ptr = (char*)(buffer_m.data());
+ ippl::Vector* dst_ptr = view.data();
+ auto rp = readpos_m;
+ using exec_space = typename Kokkos::View::execution_space;
using mdrange_t =
Kokkos::MDRangePolicy, Kokkos::IndexType, exec_space>;
Kokkos::parallel_for(
"Archive::deserialize()", mdrange_t({0, 0}, {(long int)nrecvs, Dim}),
- KOKKOS_CLASS_LAMBDA(const size_type i, const size_t d) {
- std::memcpy(&(*(view.data() + i))[d],
- buffer_m.data() + (Dim * i + d) * size + readpos_m, size);
+ KOKKOS_LAMBDA(const size_type i, const size_t d) {
+ std::memcpy(&(*(dst_ptr + i))[d], src_ptr + (Dim * i + d) * size + rp, size);
});
Kokkos::fence();
readpos_m += Dim * size * nrecvs;
diff --git a/src/Communicate/BufferHandler.h b/src/Communicate/BufferHandler.h
index 117c12f22..0655cb677 100644
--- a/src/Communicate/BufferHandler.h
+++ b/src/Communicate/BufferHandler.h
@@ -4,9 +4,155 @@
#include
#include
+#include "Types/IpplTypes.h"
+#include "Types/ViewTypes.h"
+
+#include "Utility/Logging.h"
+#include "Utility/TypeUtils.h"
+
#include "Communicate/Archive.h"
-namespace ippl {
+namespace ippl::comms {
+
+ // ---------------------------------------------------------------------
+#ifdef IPPL_SIMPLE_VIEW_STORAGE
+ template
+ using communicator_storage =
+ ippl::detail::ViewType>::view_type;
+#else
+ template
+ using communicator_storage =
+ ippl::detail::ViewType>::view_type;
+#endif
+
+#define DEFAULT_BUFFER_ALIGNMENT 1024
+ // Here's a simple class that provides an aligned buffer, by default on the host
+ // but we can specialize the constructor/destructor for other memory spaces
+ template
+ struct AlignedBuffer {
+ using memory_space = MemorySpace;
+ void* ptrOriginal{nullptr};
+ void* ptrAligned{nullptr};
+ detail::size_type space{0};
+ //
+ AlignedBuffer() {}
+ //
+ AlignedBuffer& operator=(AlignedBuffer&& other) {
+ ptrOriginal = other.ptrOriginal;
+ ptrAligned = other.ptrAligned;
+ space = other.space;
+ other.ptrOriginal = nullptr;
+ other.ptrAligned = nullptr;
+ other.space = 0;
+ return *this;
+ }
+ //
+ AlignedBuffer(std::size_t size) {
+ ptrOriginal = std::aligned_alloc(DEFAULT_BUFFER_ALIGNMENT, size);
+ ptrAligned = ptrOriginal;
+ space = size;
+ SPDLOG_TRACE("AlignedBuffer: original {}, aligned {}, size {}, space {}",
+ (void*)(ptrOriginal), (void*)(ptrAligned), size, space);
+ // sanity check should always be true when std::align used
+ assert(space >= size);
+ }
+ //
+ ~AlignedBuffer() {
+ if (ptrOriginal) {
+ SPDLOG_DEBUG("Destroying host buffer {}", ptrOriginal);
+ std::free(ptrOriginal);
+ }
+ }
+ };
+
+ // ---------------------------------------------------------------------
+#ifdef KOKKOS_ENABLE_CUDA
+ // make number a multiple of the alignment
+ inline std::int64_t to_multiple(std::int64_t num) {
+ return ((2 * num + (DEFAULT_BUFFER_ALIGNMENT - 1)) & (-DEFAULT_BUFFER_ALIGNMENT));
+ }
+
+ // Specialize buffer allocation/free for cuda
+ template <>
+ inline AlignedBuffer::AlignedBuffer(std::size_t size) {
+ void* original;
+ space = to_multiple(size);
+ cudaMalloc(&original, space);
+ if (!original) {
+ throw std::runtime_error("Error allocating cuda memory in AlignedBuffer");
+ }
+ ptrOriginal = original;
+ ptrAligned = std::align(DEFAULT_BUFFER_ALIGNMENT, size, original, space);
+ SPDLOG_TRACE("AlignedBuffer: original {}, aligned {}, size {}, space {}",
+ (void*)(ptrOriginal), (void*)(ptrAligned), size, space);
+ // sanity check should always be true when std::align used
+ assert(space >= size);
+ }
+ //
+ template <>
+ inline AlignedBuffer::~AlignedBuffer() {
+ if (ptrOriginal) {
+ SPDLOG_DEBUG("Destroying cuda buffer {}", ptrOriginal);
+ cudaFree(ptrOriginal);
+ }
+ }
+#endif
+
+ template
+ struct comm_storage_wrapper {
+ using memory_space = MemorySpace;
+ using buffer_type = communicator_storage;
+ using pointer_type = typename buffer_type::pointer_type;
+ using size_type = detail::size_type;
+ //
+ comm_storage_wrapper(const std::string& /*name*/, size_type size)
+ : view() // we will construct the view manually
+ , buffer(size) //
+ {
+ SPDLOG_TRACE("Construct: view origin {}, aligned {}", (void*)(view.data()),
+ (void*)(buffer.ptrAligned));
+ view = buffer_type((pointer_type)buffer.ptrAligned, size);
+ assert(view.data() == buffer.ptrAligned);
+ }
+ //
+ size_type size() const { return buffer.space; }
+ //
+ pointer_type data() { return view.data(); }
+
+ // Note that this makes no effort to preserve any existing data
+ void reallocBuffer(size_type newsize) {
+ // wipe the old memory, before allocating new, (help prevent out-of-space errors)
+ buffer = AlignedBuffer();
+ // allocate new
+ buffer = AlignedBuffer(newsize);
+ view = buffer_type((pointer_type)buffer.ptrAligned, newsize);
+ SPDLOG_DEBUG("Realloc : view {}, aligned {}, size {}, space {}", (void*)(view.data()),
+ (void*)(buffer.ptrAligned), newsize, buffer.space);
+ }
+ //
+ buffer_type view;
+ AlignedBuffer buffer;
+ };
+
+ // ---------------------------------------------
+ // archive wrapper around some arbitrary buffer
+ template
+ struct rma_archive {
+ using type = detail::Archive;
+ };
+
+ template
+ using rma_archive_type = rma_archive::type;
+
+#ifdef IPPL_SIMPLE_VIEW_STORAGE
+ template
+ using archive_buffer = rma_archive_type>;
+#else
+ template
+ using archive_buffer = rma_archive_type>;
+#endif
/**
* @brief Interface for memory buffer handling.
@@ -17,11 +163,11 @@ namespace ippl {
*
* @tparam MemorySpace The memory space type used for buffer allocation.
*/
- template
+ template
class BufferHandler {
public:
- using archive_type = ippl::detail::Archive;
- using buffer_type = std::shared_ptr;
+ using archive_type = Buffer;
+ using buffer_type = std::shared_ptr;
using size_type = ippl::detail::size_type;
virtual ~BufferHandler() {}
@@ -92,11 +238,12 @@ namespace ippl {
* @tparam MemorySpace The memory space type for the buffer (e.g., `Kokkos::HostSpace`).
*/
template
- class DefaultBufferHandler : public BufferHandler {
+ class DefaultBufferHandler : public BufferHandler, MemorySpace> {
public:
- using typename BufferHandler::archive_type;
- using typename BufferHandler::buffer_type;
- using typename BufferHandler::size_type;
+ using buffer_type =
+ typename BufferHandler, MemorySpace>::buffer_type;
+ using typename BufferHandler, MemorySpace>::archive_type;
+ using typename BufferHandler, MemorySpace>::size_type;
~DefaultBufferHandler() override;
@@ -106,8 +253,8 @@ namespace ippl {
* Requests a memory buffer of the specified size, with the option
* to request a buffer larger than the base size by an overallocation
* multiplier. If a sufficiently large buffer is available, it is returned. If not, the
- * largest free buffer is reallocated. If there are no free buffers available, only then a
- * new buffer is allocated.
+ * largest free buffer is reallocated. If there are no free buffers available, only then
+ * a new buffer is allocated.
*
* @param size The required buffer size.
* @param overallocation A multiplier to allocate additional buffer space.
@@ -163,7 +310,7 @@ namespace ippl {
buffer_set_type free_buffers{
&DefaultBufferHandler::bufferSizeComparator}; ///< Set of free buffers
};
-} // namespace ippl
+} // namespace ippl::comms
#include "Communicate/BufferHandler.hpp"
diff --git a/src/Communicate/BufferHandler.hpp b/src/Communicate/BufferHandler.hpp
index c6d57f0a3..f654dea7f 100644
--- a/src/Communicate/BufferHandler.hpp
+++ b/src/Communicate/BufferHandler.hpp
@@ -1,7 +1,7 @@
#ifndef IPPL_BUFFER_HANDLER_HPP
#define IPPL_BUFFER_HANDLER_HPP
-namespace ippl {
+namespace ippl::comms {
template
DefaultBufferHandler::~DefaultBufferHandler() {}
@@ -112,6 +112,7 @@ namespace ippl {
freeSize_m -= buffer->getBufferSize();
usedSize_m += buffer->getBufferSize();
+ buffer->resetReadWritePos();
free_buffers.erase(buffer);
used_buffers.insert(buffer);
return buffer;
@@ -128,6 +129,7 @@ namespace ippl {
free_buffers.erase(buffer);
buffer->reallocBuffer(requiredSize);
+ buffer->resetReadWritePos();
used_buffers.insert(buffer);
return buffer;
@@ -140,9 +142,10 @@ namespace ippl {
usedSize_m += newBuffer->getBufferSize();
used_buffers.insert(newBuffer);
+ newBuffer->resetReadWritePos();
return newBuffer;
}
-} // namespace ippl
+} // namespace ippl::comms
#endif
diff --git a/src/Communicate/Buffers.cpp b/src/Communicate/Buffers.cpp
index 04cbb1808..026633fec 100644
--- a/src/Communicate/Buffers.cpp
+++ b/src/Communicate/Buffers.cpp
@@ -32,13 +32,13 @@ namespace ippl {
}
void Communicator::deleteAllBuffers() {
- buffer_handlers_m.forAll([](BufferHandler&& bh) {
+ buffer_handlers_m->forAll([](BufferHandler&& bh) {
bh.deleteAllBuffers();
});
}
void Communicator::freeAllBuffers() {
- buffer_handlers_m.forAll([](BufferHandler&& bh) {
+ buffer_handlers_m->forAll([](BufferHandler&& bh) {
bh.freeAllBuffers();
});
}
diff --git a/src/Communicate/Buffers.hpp b/src/Communicate/Buffers.hpp
index c08dd2a69..90b477af3 100644
--- a/src/Communicate/Buffers.hpp
+++ b/src/Communicate/Buffers.hpp
@@ -20,22 +20,33 @@
// exchanging particle data between ranks.
//
+#include "Utility/Logging.h"
+#include "Utility/TypeUtils.h"
+
namespace ippl {
namespace mpi {
- template
- Communicator::buffer_type Communicator::getBuffer(size_type size,
- double overallocation) {
- auto& buffer_handler = buffer_handlers_m.get();
+ // -----------------------------------
+ template
+ Communicator::buffer_type Communicator::getBuffer(size_type size,
+ double overallocation) {
+ using memory_space = BufferType::memory_space;
- return buffer_handler.getBuffer(size * sizeof(T),
- std::max(overallocation, defaultOveralloc_m));
- }
+ auto& buffer_handler = buffer_handlers_m->get();
- template
- void Communicator::freeBuffer(Communicator::buffer_type buffer) {
- auto& buffer_handler = buffer_handlers_m.get();
+ auto b = buffer_handler.getBuffer(size * sizeof(T),
+ std::max(overallocation, defaultOveralloc_m));
+ SPDLOG_TRACE("{}, getBuffer {}, buf, {}, size {}", (void*)this,
+ ippl::debug::print_type(), (void*)(b->getData()),
+ size * sizeof(T));
+ return b;
+ }
+ template
+ void Communicator::freeBuffer(Communicator::buffer_type buffer) {
+ using memory_space = BufferType::memory_space;
+ auto& buffer_handler = buffer_handlers_m->get();
+ SPDLOG_TRACE("freeBuffer buf, {}", (void*)(buffer->getData()));
buffer_handler.freeBuffer(buffer);
}
diff --git a/src/Communicate/Collectives.hpp b/src/Communicate/Collectives.hpp
index d273242ab..0ed2aa69b 100644
--- a/src/Communicate/Collectives.hpp
+++ b/src/Communicate/Collectives.hpp
@@ -2,62 +2,60 @@
#include "Communicate/Operations.h"
-namespace ippl {
- namespace mpi {
- template
- void Communicator::gather(const T* input, T* output, int count, int root) {
- MPI_Datatype type = get_mpi_datatype(*input);
+namespace ippl::mpi {
+ template
+ void Communicator::gather(const T* input, T* output, int count, int root) {
+ MPI_Datatype type = get_mpi_datatype(*input);
- MPI_Gather(const_cast(input), count, type, output, count, type, root, *comm_m);
- }
+ MPI_Gather(const_cast(input), count, type, output, count, type, root, *comm_m);
+ }
- template
- void Communicator::scatter(const T* input, T* output, int count, int root) {
- MPI_Datatype type = get_mpi_datatype(*input);
+ template
+ void Communicator::scatter(const T* input, T* output, int count, int root) {
+ MPI_Datatype type = get_mpi_datatype(*input);
- MPI_Scatter(const_cast(input), count, type, output, count, type, root, *comm_m);
- }
+ MPI_Scatter(const_cast(input), count, type, output, count, type, root, *comm_m);
+ }
- template
- void Communicator::reduce(const T* input, T* output, int count, Op, int root) {
- MPI_Datatype type = get_mpi_datatype(*input);
+ template
+ void Communicator::reduce(const T* input, T* output, int count, Op, int root) {
+ MPI_Datatype type = get_mpi_datatype(*input);
- MPI_Op mpiOp = get_mpi_op();
+ MPI_Op mpiOp = get_mpi_op();
- MPI_Reduce(const_cast(input), output, count, type, mpiOp, root, *comm_m);
- }
+ MPI_Reduce(const_cast(input), output, count, type, mpiOp, root, *comm_m);
+ }
- template
- void Communicator::reduce(const T& input, T& output, int count, Op op, int root) {
- reduce(&input, &output, count, op, root);
- }
+ template
+ void Communicator::reduce(const T& input, T& output, int count, Op op, int root) {
+ reduce(&input, &output, count, op, root);
+ }
- template
- void Communicator::allreduce(const T* input, T* output, int count, Op) {
- MPI_Datatype type = get_mpi_datatype(*input);
+ template
+ void Communicator::allreduce(const T* input, T* output, int count, Op) {
+ MPI_Datatype type = get_mpi_datatype(*input);
- MPI_Op mpiOp = get_mpi_op();
+ MPI_Op mpiOp = get_mpi_op();
- MPI_Allreduce(const_cast(input), output, count, type, mpiOp, *comm_m);
- }
+ MPI_Allreduce(const_cast(input), output, count, type, mpiOp, *comm_m);
+ }
- template
- void Communicator::allreduce(const T& input, T& output, int count, Op op) {
- allreduce(&input, &output, count, op);
- }
+ template
+ void Communicator::allreduce(const T& input, T& output, int count, Op op) {
+ allreduce(&input, &output, count, op);
+ }
- template
- void Communicator::allreduce(T* inout, int count, Op) {
- MPI_Datatype type = get_mpi_datatype(*inout);
+ template
+ void Communicator::allreduce(T* inout, int count, Op) {
+ MPI_Datatype type = get_mpi_datatype(*inout);
- MPI_Op mpiOp = get_mpi_op();
+ MPI_Op mpiOp = get_mpi_op();
- MPI_Allreduce(MPI_IN_PLACE, inout, count, type, mpiOp, *comm_m);
- }
+ MPI_Allreduce(MPI_IN_PLACE, inout, count, type, mpiOp, *comm_m);
+ }
- template
- void Communicator::allreduce(T& inout, int count, Op op) {
- allreduce(&inout, count, op);
- }
- } // namespace mpi
-} // namespace ippl
+ template
+ void Communicator::allreduce(T& inout, int count, Op op) {
+ allreduce(&inout, count, op);
+ }
+} // namespace ippl::mpi
diff --git a/src/Communicate/Communicator.cpp b/src/Communicate/Communicator.cpp
index 0ade37738..81376de62 100644
--- a/src/Communicate/Communicator.cpp
+++ b/src/Communicate/Communicator.cpp
@@ -1,42 +1,56 @@
#include "Communicate/Communicator.h"
-namespace ippl {
- namespace mpi {
-
- Communicator::Communicator()
- : comm_m(new MPI_Comm(MPI_COMM_WORLD)) {
- MPI_Comm_rank(*comm_m, &rank_m);
- MPI_Comm_size(*comm_m, &size_m);
- }
-
- Communicator::Communicator(MPI_Comm comm) {
- comm_m = std::make_shared(comm);
- MPI_Comm_rank(*comm_m, &rank_m);
- MPI_Comm_size(*comm_m, &size_m);
- }
-
- Communicator& Communicator::operator=(MPI_Comm comm) {
- comm_m = std::make_shared(comm);
- MPI_Comm_rank(*comm_m, &rank_m);
- MPI_Comm_size(*comm_m, &size_m);
- return *this;
- }
-
- Communicator Communicator::Communicator::split(int color, int key) const {
- MPI_Comm newcomm;
- MPI_Comm_split(*comm_m, color, key, &newcomm);
- return Communicator(newcomm);
- }
-
- void Communicator::probe(int source, int tag, Status& status) {
- MPI_Probe(source, tag, *comm_m, status);
- }
-
- bool Communicator::iprobe(int source, int tag, Status& status) {
- int flag = 0;
- MPI_Iprobe(source, tag, *comm_m, &flag, status);
- return (flag != 0);
+namespace ippl::mpi {
+
+ Communicator::Communicator()
+ : buffer_handlers_m(get_buffer_handler_instance())
+ , comm_m(new MPI_Comm(MPI_COMM_WORLD)) {
+ MPI_Comm_rank(*comm_m, &rank_m);
+ MPI_Comm_size(*comm_m, &size_m);
+ }
+
+ Communicator::Communicator(MPI_Comm comm) {
+ buffer_handlers_m = get_buffer_handler_instance();
+ comm_m = std::make_shared(comm);
+ MPI_Comm_rank(*comm_m, &rank_m);
+ MPI_Comm_size(*comm_m, &size_m);
+ }
+
+ Communicator& Communicator::operator=(MPI_Comm comm) {
+ buffer_handlers_m = get_buffer_handler_instance();
+ comm_m = std::make_shared(comm);
+ MPI_Comm_rank(*comm_m, &rank_m);
+ MPI_Comm_size(*comm_m, &size_m);
+ return *this;
+ }
+
+ Communicator Communicator::Communicator::split(int color, int key) const {
+ MPI_Comm newcomm;
+ MPI_Comm_split(*comm_m, color, key, &newcomm);
+ return Communicator(newcomm);
+ }
+
+ void Communicator::probe(int source, int tag, Status& status) {
+ MPI_Probe(source, tag, *comm_m, status);
+ }
+
+ bool Communicator::iprobe(int source, int tag, Status& status) {
+ int flag = 0;
+ MPI_Iprobe(source, tag, *comm_m, &flag, status);
+ return (flag != 0);
+ }
+
+ // ---------------------------------------
+ // singleton access to buffer manager
+ // ---------------------------------------
+ std::shared_ptr Communicator::get_buffer_handler_instance() {
+ static std::shared_ptr comm_buff_handler_ptr{nullptr};
+ if (comm_buff_handler_ptr == nullptr) {
+ comm_buff_handler_ptr = std::make_shared();
+ SPDLOG_DEBUG("BufferHandler new: {}",
+ ippl::debug::print_type());
}
- } // namespace mpi
-} // namespace ippl
+ return comm_buff_handler_ptr;
+ }
+} // namespace ippl::mpi
diff --git a/src/Communicate/Communicator.h b/src/Communicate/Communicator.h
index 63886368a..114b0b4a8 100644
--- a/src/Communicate/Communicator.h
+++ b/src/Communicate/Communicator.h
@@ -5,215 +5,218 @@
#ifndef IPPL_MPI_COMMUNICATOR_H
#define IPPL_MPI_COMMUNICATOR_H
-#include
-#include
-
-#include "Communicate/BufferHandler.h"
-#include "Communicate/LoggingBufferHandler.h"
-#include "Communicate/Request.h"
-#include "Communicate/Status.h"
-
-////////////////////////////////////////////////
-// For message size check; see below
#include
#include
+#include
+#include
#include "Utility/TypeUtils.h"
#include "Communicate/Archive.h"
+#include "Communicate/BufferHandler.h"
+#include "Communicate/LogEntry.h"
+#include "Communicate/Request.h"
+#include "Communicate/Status.h"
#include "Communicate/TagMaker.h"
#include "Communicate/Tags.h"
-////////////////////////////////////////////////////
-namespace ippl {
- namespace mpi {
-
- class Communicator : public TagMaker {
- public:
- Communicator();
+////////////////////////////////////////////////////
- Communicator(MPI_Comm comm);
+namespace ippl::mpi {
- Communicator& operator=(MPI_Comm comm);
+ class Communicator : public TagMaker {
+ public:
+ Communicator();
- ~Communicator() = default;
+ Communicator(MPI_Comm comm);
- Communicator split(int color, int key) const;
+ Communicator& operator=(MPI_Comm comm);
- operator const MPI_Comm&() const noexcept { return *comm_m; }
+ ~Communicator() = default;
- int size() const noexcept { return size_m; }
+ Communicator split(int color, int key) const;
- int rank() const noexcept { return rank_m; }
+ operator const MPI_Comm&() const noexcept { return *comm_m; }
- void barrier() { MPI_Barrier(*comm_m); }
+ int size() const noexcept { return size_m; }
- void abort(int errorcode = -1) { MPI_Abort(*comm_m, errorcode); }
+ int rank() const noexcept { return rank_m; }
- /*
- * Blocking point-to-point communication
- *
- */
+ void barrier() { MPI_Barrier(*comm_m); }
- template
- void send(const T& buffer, int count, int dest, int tag);
+ void abort(int errorcode = -1) { MPI_Abort(*comm_m, errorcode); }
- template
- void send(const T* buffer, int count, int dest, int tag);
+ /*
+ * Blocking point-to-point communication
+ *
+ */
- template
- void recv(T& output, int count, int source, int tag, Status& status);
+ template
+ void send(const T& buffer, int count, int dest, int tag);
- template
- void recv(T* output, int count, int source, int tag, Status& status);
+ template
+ void send(const T* buffer, int count, int dest, int tag);
- void probe(int source, int tag, Status& status);
+ template
+ void recv(T& output, int count, int source, int tag, Status& status);
- /*
- * Non-blocking point-to-point communication
- *
- */
+ template
+ void recv(T* output, int count, int source, int tag, Status& status);
- template
- void isend(const T& buffer, int count, int dest, int tag, Request& request);
+ void probe(int source, int tag, Status& status);
- template
- void isend(const T* buffer, int count, int dest, int tag, Request& request);
+ /*
+ * Non-blocking point-to-point communication
+ *
+ */
- template
- void irecv(T& buffer, int count, int source, int tag, Request& request);
+ template
+ void isend(const T& buffer, int count, int dest, int tag, Request& request);
- template
- void irecv(T* buffer, int count, int source, int tag, Request& request);
+ template
+ void isend(const T* buffer, int count, int dest, int tag, Request& request);
- bool iprobe(int source, int tag, Status& status);
+ template
+ void irecv(T& buffer, int count, int source, int tag, Request& request);
- /*
- * Collective communication
- */
+ template
+ void irecv(T* buffer, int count, int source, int tag, Request& request);
- /* Gather the data in the given source container from all other nodes to a
- * specific node (default: 0).
- */
- template
- void gather(const T* input, T* output, int count, int root = 0);
+ bool iprobe(int source, int tag, Status& status);
- /* Scatter the data from all other nodes to a
- * specific node (default: 0).
- */
- template
- void scatter(const T* input, T* output, int count, int root = 0);
+ /*
+ * Collective communication
+ */
- /* Reduce data coming from all nodes to a specific node
- * (default: 0). Apply certain operation
- *
- */
- template
- void reduce(const T* input, T* output, int count, Op op, int root = 0);
+ /* Gather the data in the given source container from all other nodes to a
+ * specific node (default: 0).
+ */
+ template
+ void gather(const T* input, T* output, int count, int root = 0);
- template
- void reduce(const T& input, T& output, int count, Op op, int root = 0);
+ /* Scatter the data from all other nodes to a
+ * specific node (default: 0).
+ */
+ template
+ void scatter(const T* input, T* output, int count, int root = 0);
- template
- void allreduce(const T* input, T* output, int count, Op op);
+ /* Reduce data coming from all nodes to a specific node
+ * (default: 0). Apply certain operation
+ *
+ */
+ template
+ void reduce(const T* input, T* output, int count, Op op, int root = 0);
- template
- void allreduce(const T& input, T& output, int count, Op op);
+ template
+ void reduce(const T& input, T& output, int count, Op op, int root = 0);
- template
- void allreduce(T* inout, int count, Op op);
+ template
+ void allreduce(const T* input, T* output, int count, Op op);
- template
- void allreduce(T& inout, int count, Op op);
+ template
+ void allreduce(const T& input, T& output, int count, Op op);
- /////////////////////////////////////////////////////////////////////////////////////
- template
- using archive_type = detail::Archive;
+ template
+ void allreduce(T* inout, int count, Op op);
- template
- using buffer_type = std::shared_ptr>;
+ template
+ void allreduce(T& inout, int count, Op op);
- private:
- template
- using buffer_container_type = LoggingBufferHandler;
+ private:
+ template
+ using buffer_container_type = comms::DefaultBufferHandler;
- using buffer_handler_type =
- typename detail::ContainerForAllSpaces::type;
+ using buffer_handler_type =
+ typename detail::ContainerForAllSpaces::type;
- public:
- using size_type = detail::size_type;
- double getDefaultOverallocation() const { return defaultOveralloc_m; }
- void setDefaultOverallocation(double factor);
+ public:
+ template
+ using buffer_type = buffer_container_type::buffer_type;
- template
- buffer_type getBuffer(size_type size, double overallocation = 1.0);
+ public:
+ using size_type = detail::size_type;
+ double getDefaultOverallocation() const { return defaultOveralloc_m; }
+ void setDefaultOverallocation(double factor);
- void deleteAllBuffers();
- void freeAllBuffers();
+ template
+ buffer_type getBuffer(size_type size, double overallocation = 1.0);
- template
- void freeBuffer(buffer_type buffer);
+ void deleteAllBuffers();
+ void freeAllBuffers();
- const MPI_Comm& getCommunicator() const noexcept { return *comm_m; }
+ template
+ void freeBuffer(buffer_type buffer);
- template
- void recv(int src, int tag, Buffer& buffer, Archive& ar, size_type msize,
- size_type nrecvs) {
- // Temporary fix. MPI communication seems to have problems when the
- // count argument exceeds the range of int, so large messages should
- // be split into smaller messages
- if (msize > INT_MAX) {
- std::cerr << "Message size exceeds range of int" << std::endl;
- this->abort();
- }
- MPI_Status status;
- MPI_Recv(ar.getBuffer(), msize, MPI_BYTE, src, tag, *comm_m, &status);
+ const MPI_Comm& getCommunicator() const noexcept { return *comm_m; }
- buffer.deserialize(ar, nrecvs);
+ template
+ void recv(int src, int tag, Buffer& buffer, Archive& ar, size_type msize,
+ size_type nrecvs) {
+ // Temporary fix. MPI communication seems to have problems when the
+ // count argument exceeds the range of int, so large messages should
+ // be split into smaller messages
+ if (msize > INT_MAX) {
+ std::cerr << "Message size exceeds range of int" << std::endl;
+ this->abort();
}
-
- template
- void isend(int dest, int tag, Buffer& buffer, Archive& ar, MPI_Request& request,
- size_type nsends) {
- if (ar.getSize() > INT_MAX) {
- std::cerr << "Message size exceeds range of int" << std::endl;
- this->abort();
- }
- buffer.serialize(ar, nsends);
- MPI_Isend(ar.getBuffer(), ar.getSize(), MPI_BYTE, dest, tag, *comm_m, &request);
+ MPI_Status status;
+ MPI_Recv(ar.getData(), msize, MPI_BYTE, src, tag, *comm_m, &status);
+ SPDLOG_DEBUG("Recv buf {}, size {:04}, src {:02}, tag {:04}", (void*)(ar.getData()),
+ msize, src, tag);
+ buffer.deserialize(ar, nrecvs);
+ }
+
+ template
+ void isend(int dest, int tag, Buffer& buffer, Archive& ar, MPI_Request& request,
+ size_type nsends) //
+ {
+ if (ar.getSize() > INT_MAX) {
+ std::cerr << "Message size exceeds range of int" << std::endl;
+ this->abort();
}
-
- template
- void irecv(int src, int tag, Archive& ar, MPI_Request& request, size_type msize) {
- if (msize > INT_MAX) {
- std::cerr << "Message size exceeds range of int" << std::endl;
- this->abort();
- }
- MPI_Irecv(ar.getBuffer(), msize, MPI_BYTE, src, tag, *comm_m, &request);
+ buffer.serialize(ar, nsends);
+ MPI_Isend(ar.getData(), ar.getSize(), MPI_BYTE, dest, tag, *comm_m, &request);
+ SPDLOG_DEBUG("Isend buf {}, size {:04}, dst {:02}, tag {:04}, req {}",
+ (void*)(ar.getData()), ar.getSize(), dest, tag,
+ static_cast(request));
+ }
+
+ template
+ void irecv(int src, int tag, Archive& ar, MPI_Request& request, size_type msize) {
+ if (msize > INT_MAX) {
+ std::cerr << "Message size exceeds range of int" << std::endl;
+ this->abort();
}
- void printLogs(const std::string& filename);
+ MPI_Irecv(ar.getData(), msize, MPI_BYTE, src, tag, *comm_m, &request);
+ SPDLOG_DEBUG("Irecv buf {}, size {:04}, src {:02}, tag {:04}, req {}",
+ (void*)(ar.getData()), msize, src, tag, static_cast(request));
+ }
+
+ void printLogs(const std::string& filename);
+
+ private:
+ std::vector gatherLocalLogs();
+ void sendLogsToRank0(const std::vector& localLogs);
+ std::vector gatherLogsFromAllRanks(const std::vector& localLogs);
+ void writeLogsToFile(const std::vector& allLogs, const std::string& filename);
- private:
- std::vector gatherLocalLogs();
- void sendLogsToRank0(const std::vector& localLogs);
- std::vector gatherLogsFromAllRanks(const std::vector& localLogs);
- void writeLogsToFile(const std::vector& allLogs, const std::string& filename);
+ std::shared_ptr buffer_handlers_m;
+ double defaultOveralloc_m = 1.0;
- buffer_handler_type buffer_handlers_m;
+ /////////////////////////////////////////////////////////////////////////////////////
- double defaultOveralloc_m = 1.0;
+ protected:
+ std::shared_ptr comm_m;
+ int size_m;
+ int rank_m;
- /////////////////////////////////////////////////////////////////////////////////////
+ public:
+ std::shared_ptr get_buffer_handler_instance();
+ };
- protected:
- std::shared_ptr comm_m;
- int size_m;
- int rank_m;
- };
- } // namespace mpi
-} // namespace ippl
+} // namespace ippl::mpi
#include "Communicate/Collectives.hpp"
#include "Communicate/PointToPoint.hpp"
diff --git a/src/Communicate/CommunicatorLogging.cpp b/src/Communicate/CommunicatorLogging.cpp
index 92e821ebd..3c3000695 100644
--- a/src/Communicate/CommunicatorLogging.cpp
+++ b/src/Communicate/CommunicatorLogging.cpp
@@ -6,119 +6,122 @@
#include "Utility/Inform.h"
#include "Communicate/Communicator.h"
-#include "Communicate/LogEntry.h"
-
-namespace ippl {
- namespace mpi {
- void Communicator::printLogs(const std::string& filename) {
- std::vector localLogs = gatherLocalLogs();
-
- std::vector allLogs;
- if (rank() == 0) {
- allLogs = gatherLogsFromAllRanks(localLogs);
- } else {
- sendLogsToRank0(localLogs);
- }
+#include "Communicate/LoggingBufferHandler.h"
- if (rank() == 0) {
- writeLogsToFile(allLogs, filename);
- }
+namespace ippl::mpi {
+ void Communicator::printLogs(const std::string& filename) {
+ std::vector localLogs = gatherLocalLogs();
+
+ std::vector allLogs;
+ if (rank() == 0) {
+ allLogs = gatherLogsFromAllRanks(localLogs);
+ } else {
+ sendLogsToRank0(localLogs);
+ }
+
+ if (rank() == 0) {
+ writeLogsToFile(allLogs, filename);
}
+ }
- std::vector Communicator::gatherLocalLogs() {
- std::vector localLogs;
+ template
+ struct is_a_logger : std::false_type {};
- buffer_handlers_m.forAll([&](auto& loggingHandler) {
+ template
+ struct is_a_logger > : std::true_type {};
+
+ std::vector