diff --git a/documentation/developer/simpleTape.cpp b/documentation/developer/simpleTape.cpp index 34f1cc23..aecd805d 100644 --- a/documentation/developer/simpleTape.cpp +++ b/documentation/developer/simpleTape.cpp @@ -154,7 +154,8 @@ struct SimpleTape : public codi::ReverseTapeInterface { values.addSection("Adjoint vector"); values.addLongEntry("Number of adjoints", (1 + maxIdentifier)); - values.addDoubleEntry("Memory allocated", sizeof(double) * (1 + maxIdentifier), true, true); + values.addDoubleEntry("Memory allocated", sizeof(double) * (1 + maxIdentifier), + codi::TapeValues::LocalReductionOperation::Sum, true, true); values.addSection("Index manager"); values.addLongEntry("Max. live indices", (1 + maxIdentifier)); diff --git a/include/codi/expressions/real/binaryOperators.hpp b/include/codi/expressions/real/binaryOperators.hpp index 2e0524b8..2efb9b4a 100644 --- a/include/codi/expressions/real/binaryOperators.hpp +++ b/include/codi/expressions/real/binaryOperators.hpp @@ -398,7 +398,8 @@ namespace codi { /// \copydoc codi::BinaryOperation::gradientB() template - static CODI_INLINE RealTraits::PassiveReal gradientB(ArgA const& argA, ArgB const& argB, Real const& result) { + static CODI_INLINE RealTraits::PassiveReal gradientB(ArgA const& argA, ArgB const& argB, + Real const& result) { CODI_UNUSED(argA, argB, result); return 0.0; @@ -525,7 +526,8 @@ namespace codi { /// \copydoc codi::BinaryOperation::gradientB() template - static CODI_INLINE RealTraits::PassiveReal gradientB(ArgA const& argA, ArgB const& argB, Real const& result) { + static CODI_INLINE RealTraits::PassiveReal gradientB(ArgA const& argA, ArgB const& argB, + Real const& result) { CODI_UNUSED(argA, argB, result); return 0.0; @@ -743,7 +745,8 @@ namespace codi { /// \copydoc codi::BinaryOperation::gradientA() template - static CODI_INLINE RealTraits::PassiveReal gradientA(ArgA const& argA, ArgB const& argB, Real const& result) { + static CODI_INLINE RealTraits::PassiveReal gradientA(ArgA const& argA, ArgB const& argB, + Real const& result) { CODI_UNUSED(argA, argB, result); return 1.0; diff --git a/include/codi/tapes/data/blockData.hpp b/include/codi/tapes/data/blockData.hpp index 1771bc43..805f26d8 100644 --- a/include/codi/tapes/data/blockData.hpp +++ b/include/codi/tapes/data/blockData.hpp @@ -201,8 +201,8 @@ namespace codi { double memoryAlloc = (double)allocedSize * (double)entrySize; values.addUnsignedLongEntry("Total number", dataEntries); - values.addDoubleEntry("Memory used", memoryUsed, true, false); - values.addDoubleEntry("Memory allocated", memoryAlloc, false, true); + values.addDoubleEntry("Memory used", memoryUsed, TapeValues::LocalReductionOperation::Sum, true, false); + values.addDoubleEntry("Memory allocated", memoryAlloc, TapeValues::LocalReductionOperation::Sum, false, true); } /// \copydoc DataInterface::extractPosition diff --git a/include/codi/tapes/data/chunkedData.hpp b/include/codi/tapes/data/chunkedData.hpp index 6f2282da..ef8f3fda 100644 --- a/include/codi/tapes/data/chunkedData.hpp +++ b/include/codi/tapes/data/chunkedData.hpp @@ -265,8 +265,8 @@ namespace codi { values.addUnsignedLongEntry("Total number", dataEntries); values.addUnsignedLongEntry("Number of chunks", numberOfChunks); - values.addDoubleEntry("Memory used", memoryUsed, true, false); - values.addDoubleEntry("Memory allocated", memoryAlloc, false, true); + values.addDoubleEntry("Memory used", memoryUsed, TapeValues::LocalReductionOperation::Sum, true, false); + values.addDoubleEntry("Memory allocated", memoryAlloc, TapeValues::LocalReductionOperation::Sum, false, true); } /// \copydoc DataInterface::extractPosition diff --git a/include/codi/tapes/indices/linearIndexManager.hpp b/include/codi/tapes/indices/linearIndexManager.hpp index 74fe2af1..132784c1 100644 --- a/include/codi/tapes/indices/linearIndexManager.hpp +++ b/include/codi/tapes/indices/linearIndexManager.hpp @@ -105,7 +105,11 @@ namespace codi { /// \copydoc IndexManagerInterface::addToTapeValues

/// Implementation: Adds maximum live indices. void addToTapeValues(TapeValues& values) const { - values.addLongEntry("Max. live indices", getLargestCreatedIndex()); + TapeValues::LocalReductionOperation constexpr operation = NeedsStaticStorage + ? TapeValues::LocalReductionOperation::Max + : TapeValues::LocalReductionOperation::Sum; + + values.addLongEntry("Max. live indices", getLargestCreatedIndex(), operation); } /// \copydoc IndexManagerInterface::freeIndex

diff --git a/include/codi/tapes/indices/multiUseIndexManager.hpp b/include/codi/tapes/indices/multiUseIndexManager.hpp index 75152c5d..97120cb9 100644 --- a/include/codi/tapes/indices/multiUseIndexManager.hpp +++ b/include/codi/tapes/indices/multiUseIndexManager.hpp @@ -93,7 +93,11 @@ namespace codi { double memoryindexUseVector = (double)indexUse.size() * (double)(sizeof(Index)); - values.addDoubleEntry("Memory: index use vector", memoryindexUseVector, true, true); + TapeValues::LocalReductionOperation constexpr operation = NeedsStaticStorage + ? TapeValues::LocalReductionOperation::Max + : TapeValues::LocalReductionOperation::Sum; + + values.addDoubleEntry("Memory: index use vector", memoryindexUseVector, operation, true, true); } /// \copydoc ReuseIndexManager::assignIndex diff --git a/include/codi/tapes/indices/parallelReuseIndexManager.hpp b/include/codi/tapes/indices/parallelReuseIndexManager.hpp index 705df28e..7fbe1dd6 100644 --- a/include/codi/tapes/indices/parallelReuseIndexManager.hpp +++ b/include/codi/tapes/indices/parallelReuseIndexManager.hpp @@ -136,7 +136,10 @@ namespace codi { void addToTapeValues(TapeValues& values) const { unsigned long maximumGlobalIndex = globalMaximumIndex(); - values.addUnsignedLongEntry("Max. live indices", maximumGlobalIndex); + // As maximumGlobalIndex is static, it uses a local maximum reduction. + TapeValues::LocalReductionOperation constexpr operation = TapeValues::LocalReductionOperation::Max; + + values.addUnsignedLongEntry("Max. live indices", maximumGlobalIndex, operation); // The number of current live indices cannot be computed from one instance alone. // It equals the number of maximum live indices minus the number of indices stored across all instances. diff --git a/include/codi/tapes/indices/reuseIndexManager.hpp b/include/codi/tapes/indices/reuseIndexManager.hpp index 05af2e6a..e5fc1a0a 100644 --- a/include/codi/tapes/indices/reuseIndexManager.hpp +++ b/include/codi/tapes/indices/reuseIndexManager.hpp @@ -93,8 +93,12 @@ namespace codi { unsigned long storedIndices = this->usedIndicesPos + this->unusedIndicesPos; long currentLiveIndices = maximumGlobalIndex - storedIndices; - values.addUnsignedLongEntry("Max. live indices", maximumGlobalIndex); - values.addLongEntry("Cur. live indices", currentLiveIndices); + TapeValues::LocalReductionOperation constexpr operation = NeedsStaticStorage + ? TapeValues::LocalReductionOperation::Max + : TapeValues::LocalReductionOperation::Sum; + + values.addUnsignedLongEntry("Max. live indices", maximumGlobalIndex, operation); + values.addLongEntry("Cur. live indices", currentLiveIndices, operation); Base::addToTapeValues(values); } diff --git a/include/codi/tapes/indices/reuseIndexManagerBase.hpp b/include/codi/tapes/indices/reuseIndexManagerBase.hpp index c007bf24..bbd41c46 100644 --- a/include/codi/tapes/indices/reuseIndexManagerBase.hpp +++ b/include/codi/tapes/indices/reuseIndexManagerBase.hpp @@ -104,6 +104,11 @@ namespace codi { return static_cast(*this); } + /// Const cast to the implementation. + CODI_INLINE Impl const& cast() const { + return static_cast(*this); + } + /// Method to generate new indices. Only called when unusedIndices is empty. CODI_NO_INLINE void generateNewIndices() { cast().generateNewIndices(); @@ -237,9 +242,13 @@ namespace codi { double memoryStoredIndices = (double)storedIndices * (double)(sizeof(Index)); double memoryAllocatedIndices = (double)allocatedIndices * (double)(sizeof(Index)); - values.addUnsignedLongEntry("Indices stored", storedIndices); - values.addDoubleEntry("Memory used", memoryStoredIndices, true, false); - values.addDoubleEntry("Memory allocated", memoryAllocatedIndices, false, true); + TapeValues::LocalReductionOperation constexpr operation = cast().NeedsStaticStorage + ? TapeValues::LocalReductionOperation::Max + : TapeValues::LocalReductionOperation::Sum; + + values.addUnsignedLongEntry("Indices stored", storedIndices, operation); + values.addDoubleEntry("Memory used", memoryStoredIndices, operation, true, false); + values.addDoubleEntry("Memory allocated", memoryAllocatedIndices, operation, false, true); } /// @} diff --git a/include/codi/tapes/jacobianBaseTape.hpp b/include/codi/tapes/jacobianBaseTape.hpp index cf43d0ed..6cf3af75 100644 --- a/include/codi/tapes/jacobianBaseTape.hpp +++ b/include/codi/tapes/jacobianBaseTape.hpp @@ -48,6 +48,7 @@ #include "../misc/macros.hpp" #include "../misc/mathUtility.hpp" #include "../misc/memberStore.hpp" +#include "../traits/adjointVectorTraits.hpp" #include "../traits/computationTraits.hpp" #include "../traits/expressionTraits.hpp" #include "commonTapeImplementation.hpp" @@ -494,9 +495,13 @@ namespace codi { size_t nAdjoints = indexManager.get().getLargestCreatedIndex(); double memoryAdjoints = static_cast(nAdjoints) * static_cast(sizeof(Gradient)); + bool constexpr globalAdjoints = AdjointVectorTraits::IsGlobal::value; + TapeValues::LocalReductionOperation constexpr operation = + globalAdjoints ? TapeValues::LocalReductionOperation::Max : TapeValues::LocalReductionOperation::Sum; + values.addSection("Adjoint vector"); - values.addUnsignedLongEntry("Number of adjoints", nAdjoints); - values.addDoubleEntry("Memory allocated", memoryAdjoints, true, true); + values.addUnsignedLongEntry("Number of adjoints", nAdjoints, operation); + values.addDoubleEntry("Memory allocated", memoryAdjoints, operation, true, true); values.addSection("Index manager"); indexManager.get().addToTapeValues(values); diff --git a/include/codi/tapes/misc/tapeValues.hpp b/include/codi/tapes/misc/tapeValues.hpp index 9b6862a4..eb5c4fef 100644 --- a/include/codi/tapes/misc/tapeValues.hpp +++ b/include/codi/tapes/misc/tapeValues.hpp @@ -73,6 +73,12 @@ namespace codi { * - getUsedMemorySize(): Get the used memory size. */ struct TapeValues { + public: + enum class LocalReductionOperation { + Sum, + Max + }; + private: enum class EntryType { Double, @@ -84,11 +90,14 @@ namespace codi { public: std::string name; EntryType type; + LocalReductionOperation operation; size_t pos; - Entry() : name(), type(), pos() {} + Entry() : name(), type(), operation(), pos() {} - Entry(std::string const& name, EntryType const& type, size_t const& pos) : name(name), type(type), pos(pos) {} + Entry(std::string const& name, EntryType const& type, LocalReductionOperation const& operation, + size_t const& pos) + : name(name), type(type), operation(operation), pos(pos) {} }; struct Section { @@ -116,8 +125,8 @@ namespace codi { TapeValues(std::string const& tapeName) : sections(), doubleData(), longData(), unsignedLongData(), usedMemoryIndex(0), allocatedMemoryIndex(1) { addSection(tapeName); - addEntryInternal("Total memory used", EntryType::Double, doubleData, 0.0); - addEntryInternal("Total memory allocated", EntryType::Double, doubleData, 0.0); + addEntryInternal("Total memory used", EntryType::Double, LocalReductionOperation::Sum, doubleData, 0.0); + addEntryInternal("Total memory allocated", EntryType::Double, LocalReductionOperation::Sum, doubleData, 0.0); } /*******************************************************************************/ @@ -125,9 +134,10 @@ namespace codi { /// @{ /// Add double entry. If it is a memory entry, it should be in bytes. - void addDoubleEntry(std::string const& name, double const& value, bool usedMem = false, + void addDoubleEntry(std::string const& name, double const& value, + LocalReductionOperation operation = LocalReductionOperation::Sum, bool usedMem = false, bool allocatedMem = false) { - addEntryInternal(name, EntryType::Double, doubleData, value); + addEntryInternal(name, EntryType::Double, operation, doubleData, value); if (usedMem) { doubleData[usedMemoryIndex] += value; @@ -139,8 +149,9 @@ namespace codi { } /// Add long entry. - void addLongEntry(std::string const& name, long const& value) { - addEntryInternal(name, EntryType::Long, longData, value); + void addLongEntry(std::string const& name, long const& value, + LocalReductionOperation operation = LocalReductionOperation::Sum) { + addEntryInternal(name, EntryType::Long, operation, longData, value); } /// Add section. All further entries are added under this section. @@ -149,8 +160,9 @@ namespace codi { } /// Add unsigned long entry. - void addUnsignedLongEntry(std::string const& name, unsigned long const& value) { - addEntryInternal(name, EntryType::UnsignedLong, unsignedLongData, value); + void addUnsignedLongEntry(std::string const& name, unsigned long const& value, + LocalReductionOperation operation = LocalReductionOperation::Sum) { + addEntryInternal(name, EntryType::UnsignedLong, operation, unsignedLongData, value); } /// @} @@ -227,24 +239,46 @@ namespace codi { /// Perform entry-wise additions. void combineData(TapeValues const& other) { - - // Basic checks to ensure that we add tape values of the same tape type. + // Size check for the number of sections. codiAssert(this->sections.size() == other.sections.size()); - codiAssert(this->sections.size() == 0 || this->sections[0].name == other.sections[0].name); - - // Size checks for the subsequent loops. - codiAssert(this->doubleData.size() == other.doubleData.size()); - codiAssert(this->longData.size() == other.longData.size()); - codiAssert(this->unsignedLongData.size() == other.unsignedLongData.size()); - for (size_t i = 0; i < this->doubleData.size(); ++i) { - this->doubleData[i] += other.doubleData[i]; - } - for (size_t i = 0; i < this->longData.size(); ++i) { - this->longData[i] += other.longData[i]; - } - for (size_t i = 0; i < this->unsignedLongData.size(); ++i) { - this->unsignedLongData[i] += other.unsignedLongData[i]; + for (size_t section = 0; section < this->sections.size(); ++section) { + auto& thisSection = this->sections[section]; + auto const& otherSection = other.sections[section]; + + // Basic check to ensure that we combine identically structured tape values. + codiAssert(thisSection.name == otherSection.name); + + // Size check for the number of entries. + codiAssert(thisSection.data.size() == otherSection.data.size()); + + for (size_t entry = 0; entry < thisSection.data.size(); ++entry) { + auto& thisEntry = thisSection.data[entry]; + auto const& otherEntry = otherSection.data[entry]; + + // Basic checks to ensure that we combine identically structured tape values. + codiAssert(thisEntry.name == otherEntry.name); + codiAssert(thisEntry.type == otherEntry.type); + codiAssert(thisEntry.operation == otherEntry.operation); + + switch (thisEntry.type) { + case EntryType::Double: { + performLocalReduction(this->doubleData[thisEntry.pos], other.doubleData[otherEntry.pos], + thisEntry.operation); + break; + } + case EntryType::Long: { + performLocalReduction(this->longData[thisEntry.pos], other.longData[otherEntry.pos], + thisEntry.operation); + break; + } + case EntryType::UnsignedLong: { + performLocalReduction(this->unsignedLongData[thisEntry.pos], other.unsignedLongData[otherEntry.pos], + thisEntry.operation); + break; + } + } + } } } @@ -288,7 +322,22 @@ namespace codi { private: template - void addEntryInternal(std::string const& name, EntryType const& type, std::vector& vector, T const& value) { + void performLocalReduction(T& lhs, T const& rhs, LocalReductionOperation operation) { + switch (operation) { + case LocalReductionOperation::Sum: { + lhs += rhs; + break; + } + case LocalReductionOperation::Max: { + lhs = std::max(lhs, rhs); + break; + } + } + } + + template + void addEntryInternal(std::string const& name, EntryType const& type, LocalReductionOperation const& operation, + std::vector& vector, T const& value) { size_t entryPos = vector.size(); vector.push_back(value); @@ -296,7 +345,7 @@ namespace codi { addSection("General"); } - sections.back().data.push_back(Entry(name, type, entryPos)); + sections.back().data.push_back(Entry(name, type, operation, entryPos)); } std::string formatEntry(Entry const& entry, int maximumFieldSize) const { diff --git a/include/codi/tapes/primalValueBaseTape.hpp b/include/codi/tapes/primalValueBaseTape.hpp index 76bf43d2..3172e734 100644 --- a/include/codi/tapes/primalValueBaseTape.hpp +++ b/include/codi/tapes/primalValueBaseTape.hpp @@ -562,11 +562,11 @@ namespace codi { values.addSection("Adjoint vector"); values.addUnsignedLongEntry("Number of adjoints", nAdjoints); - values.addDoubleEntry("Memory allocated", memoryAdjoints, true, true); + values.addDoubleEntry("Memory allocated", memoryAdjoints, TapeValues::LocalReductionOperation::Sum, true, true); values.addSection("Primal vector"); values.addUnsignedLongEntry("Number of primals", nPrimals); - values.addDoubleEntry("Memory allocated", memoryPrimals, true, true); + values.addDoubleEntry("Memory allocated", memoryPrimals, TapeValues::LocalReductionOperation::Sum, true, true); values.addSection("Index manager"); indexManager.get().addToTapeValues(values); diff --git a/include/codi/tools/parallel/parallelToolbox.hpp b/include/codi/tools/parallel/parallelToolbox.hpp index f211a2af..71abc8fc 100644 --- a/include/codi/tools/parallel/parallelToolbox.hpp +++ b/include/codi/tools/parallel/parallelToolbox.hpp @@ -84,7 +84,7 @@ namespace codi { using StaticThreadLocalPointer = CODI_DD(CODI_T(T_StaticThreadLocalPointer), CODI_T(StaticThreadLocalPointerInterface)); - using Synchronization = CODI_DD(T_Synchronization, DefaultSynchronization); ///< See codi::ParallelToolbox. + using Synchronization = CODI_DD(T_Synchronization, DefaultSynchronization); ///< See codi::ParallelToolbox. using Lock = codi::Lock; ///< See codi::Lock. using ReadWriteMutex = codi::ReadWriteMutex>; ///< See codi::ReadWriteMutex. diff --git a/include/codi/traits/adjointVectorTraits.hpp b/include/codi/traits/adjointVectorTraits.hpp new file mode 100644 index 00000000..4ebf0d1a --- /dev/null +++ b/include/codi/traits/adjointVectorTraits.hpp @@ -0,0 +1,57 @@ +/* + * CoDiPack, a Code Differentiation Package + * + * Copyright (C) 2015-2024 Chair for Scientific Computing (SciComp), University of Kaiserslautern-Landau + * Homepage: http://www.scicomp.uni-kl.de + * Contact: Prof. Nicolas R. Gauger (codi@scicomp.uni-kl.de) + * + * Lead developers: Max Sagebaum, Johannes Blühdorn (SciComp, University of Kaiserslautern-Landau) + * + * This file is part of CoDiPack (http://www.scicomp.uni-kl.de/software/codi). + * + * CoDiPack is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * CoDiPack is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * You should have received a copy of the GNU + * General Public License along with CoDiPack. + * If not, see . + * + * For other licensing options please contact us. + * + * Authors: + * - SciComp, University of Kaiserslautern-Landau: + * - Max Sagebaum + * - Johannes Blühdorn + * - Former members: + * - Tim Albring + */ +#pragma once + +#include + +/** \copydoc codi::Namespace */ +namespace codi { + + template + struct ThreadSafeGlobalAdjoints; + + /// Traits for atomic types. + namespace AdjointVectorTraits { + + /// Whether the adjoint vector is global, that is, shared among different tapes. + template + struct IsGlobal : std::false_type {}; + +#ifndef DOXYGEN_DISABLE + template + struct IsGlobal> : std::true_type {}; +#endif + } +} diff --git a/tests/general/include/tests/expressions/testOneArgumentExpr1.hpp b/tests/general/include/tests/expressions/testOneArgumentExpr1.hpp index 72b4ea28..3bf26679 100644 --- a/tests/general/include/tests/expressions/testOneArgumentExpr1.hpp +++ b/tests/general/include/tests/expressions/testOneArgumentExpr1.hpp @@ -107,6 +107,6 @@ struct TestOneArgumentExpr1 : public TestInterface { y[18] = ldexp(x[0], 7); // R int temp = 0; y[19] = frexp(x[0], &temp); // R - y[20] = asinh(x[0]); // R + y[20] = asinh(x[0]); // R } };