43#include "../tapes/interfaces/fullTapeInterface.hpp"
44#include "../tapes/statementEvaluators/statementEvaluatorInterface.hpp"
65 template<
typename T_Tape,
typename T_Impl>
70 using Real =
typename Tape::Real;
77 Real* primals =
nullptr;
84 primals = tape.getPrimalVector();
114 data->cast().applyToInput(*
id);
119 data->cast().applyToOutput(*
id);
135 impl.applyToInput(rhsIdentifiers[i]);
137 impl.applyPostInputLogic();
139 impl.applyToOutput(lhsIndex);
140 impl.applyPostOutputLogic();
148 size_t& linearAdjointPosition,
char* stmtData) {
149 using StatementEvaluator =
typename Tape::StatementEvaluator;
154 StatementEvaluator::template call<codi::StatementCall::WriteInformation, Tape>(evalHandle, writeInfo, primals,
155 nPassiveValues, stmtData);
157 StatementEvaluator::template call<codi::StatementCall::IterateInputs, Tape>(
158 evalHandle, linearAdjointPosition,
reinterpret_cast<void (*)(
Identifier*,
void*)
>(applyToInput_func),
this,
159 nPassiveValues, stmtData);
160 impl.applyPostInputLogic();
162 StatementEvaluator::template call<codi::StatementCall::IterateOutputs, Tape>(
163 evalHandle, linearAdjointPosition,
reinterpret_cast<void (*)(
Identifier*,
void*)
>(applyToOutput_func),
this,
164 nPassiveValues, stmtData);
165 impl.applyPostOutputLogic();
167 if (Tape::LinearIndexHandling) {
180 func.template call<codi::LowLevelFunctionEntryCallKind::IterateInputs>(
181 &tape, llfData,
reinterpret_cast<void (*)(
Identifier*,
void*)
>(applyToInput_func),
this);
182 impl.applyPostInputLogic();
185 func.template call<codi::LowLevelFunctionEntryCallKind::IterateOutputs>(
186 &tape, llfData,
reinterpret_cast<void (*)(
Identifier*,
void*)
>(applyToOutput_func),
this);
187 impl.applyPostOutputLogic();
193 return static_cast<Impl&
>(*this);
202 template<
typename T_Identifier>
204 using Identifier =
CODI_DD(T_Identifier,
int);
205 using UnsignedIdentifier = std::make_signed_t<Identifier>;
239 gen = *
stack.begin();
278 template<
typename T_Identifier,
typename T_Lifetime =
int>
281 using Identifier =
CODI_DD(T_Identifier,
int);
282 using Lifetime =
CODI_DD(T_Lifetime,
int);
284 Identifier invalidId;
288 std::vector<Lifetime> stmtLivetime = {};
290 std::vector<Lifetime> llfLivetimeOffsets = {};
292 std::vector<Identifier> llfLivetimesId = {};
294 std::vector<Lifetime> llfLivetimes = {};
296 Lifetime curLLFOutputPos = 0;
297 Lifetime endLLFOutputPos = 0;
305 llfLivetimeOffsets.push_back(0);
314 return stmtLivetime[stmtId] < invalidId;
320 if (stmtLivetime[stmtId] < invalidId) {
321 auto [start, end] = getLLFRange(stmtLivetime[stmtId]);
323 curLLFOutputPos = start;
324 endLLFOutputPos = end;
332 Lifetime r = stmtLivetime[stmtId];
335 auto iterPos = std::lower_bound(llfLivetimesId.begin() + curLLFOutputPos,
336 llfLivetimesId.begin() + endLLFOutputPos, outputId);
339 int pos = std::distance(llfLivetimesId.begin(), iterPos);
340 r = llfLivetimes[pos];
353 if (stmtLivetime[stmtId] == invalidId) {
354 stmtLivetime[stmtId] = lifetime;
359 auto [start, end] = getLLFRange(stmtLivetime[stmtId]);
361 auto iterPos = std::lower_bound(llfLivetimesId.begin() + start, llfLivetimesId.begin() + end, outputId);
364 int pos = std::distance(llfLivetimesId.begin(), iterPos);
365 llfLivetimes[pos] = lifetime;
372 llfLivetimesId.push_back(
id);
373 llfLivetimes.push_back(invalidId);
379 if (0 == outputSize || outputSize > 1) {
383 llfLivetimeOffsets.push_back(llfLivetimesId.size());
384 stmtLivetime.push_back(generateLLFRange());
387 stmtLivetime.push_back(invalidId);
390 llfLivetimesId.pop_back();
391 llfLivetimes.pop_back();
402 CODI_INLINE std::pair<Lifetime, Lifetime> getLLFRange(Lifetime lifetime) {
403 Lifetime offset = -lifetime - 2;
404 return {llfLivetimeOffsets[offset], llfLivetimeOffsets[offset + 1]};
409 return -(Identifier)llfLivetimeOffsets.size();
413 void sortCurrentRange() {
415 Lifetime start = llfLivetimeOffsets.back();
416 Lifetime end = llfLivetimesId.size();
420 for (Lifetime i = start; i < end; i += 1) {
425 std::sort(llfLivetimesId.begin() + start, llfLivetimesId.end());
426 llfLivetimesId.erase(std::unique(llfLivetimesId.begin() + start, llfLivetimesId.end()), llfLivetimesId.end());
427 llfLivetimes.resize(llfLivetimesId.size());
450 template<
typename T_Tape,
typename T_Lifetime =
int>
458 using Real =
typename Tape::Real;
459 using Identifier =
typename Tape::Identifier;
460 using EvalHandle =
typename Tape::EvalHandle;
463 using IdLivetimesMap = std::multimap<Lifetime, std::pair<Identifier, Identifier>>;
465 Identifier invalidId = {};
466 Identifier passiveId = {};
469 Lifetime hotLiveTimeThreshold = 500;
470 Identifier idMapSize = {};
472 IdentifierGenerator<Identifier> generatorHot = {};
473 IdentifierGenerator<Identifier> generatorCold = {};
475 LifetimeManager<Identifier, Lifetime> lifetimes;
490 : invalidId(tape.getInvalidIndex()), passiveId(tape.getPassiveIndex()), tape(tape), lifetimes(invalidId) {
492 generatorCold.init(startCold, -1);
493 generatorHot.init(1, 1);
495 idMapSize = startCold + 1;
500 this->hotLiveTimeThreshold = hotLiveTimeThreshold;
517 std::vector<Identifier> translateMap = {};
519 IdLivetimesMap currentIdLivetimes = {};
522 CODI_INLINE HandleTranslate(IdentifierCacheOptimizerHotCold* p) : Base(p->tape), parent(p) {
523 translateMap.resize(parent->idMapSize, parent->invalidId);
525 translateMap[parent->passiveId] = parent->passiveId;
544 if (parent->passiveId ==
id) {
546 parent->lifetimes.getLifetime(curStmtId,
id);
551 Lifetime livetime = parent->lifetimes.getLifetime(curStmtId,
id);
556 if (transId != parent->invalidId) {
560 bool isHot = livetime < parent->hotLiveTimeThreshold;
564 transId = parent->generatorHot.generate();
566 transId = parent->generatorCold.generate();
569 currentIdLivetimes.emplace(curStmtId + livetime, std::make_pair(
id, transId));
577 using Iter =
typename IdLivetimesMap::iterator;
578 Iter cur = currentIdLivetimes.begin();
579 Iter end = currentIdLivetimes.end();
582 for (; cur != end; cur++) {
583 if (cur->first > curStmtId) {
587 bool isHot = parent->generatorHot.isHandledByThis(cur->second.second);
589 parent->generatorHot.free(cur->second.second);
591 parent->generatorCold.free(cur->second.second);
593 translateMap[cur->second.first] = parent->invalidId;
597 currentIdLivetimes.erase(currentIdLivetimes.begin(), cur);
599 parent->lifetimes.prepareStatementRead(curStmtId);
615 struct HandleHotColdAnalysis :
public ApplyIdentifierModification<Tape, HandleHotColdAnalysis> {
618 IdentifierCacheOptimizerHotCold* parent;
620 std::vector<Lifetime> idLastUseInStmt = {};
621 std::vector<Lifetime> idCreatedInStmt = {};
626 CODI_INLINE HandleHotColdAnalysis(IdentifierCacheOptimizerHotCold* p) : Base(p->tape), parent(p) {
627 idLastUseInStmt.resize(parent->idMapSize, parent->invalidId);
628 idCreatedInStmt.resize(parent->idMapSize, parent->invalidId);
633 Lifetime& createStmtId = idCreatedInStmt[id];
634 Lifetime& lastUseStmtId = idLastUseInStmt[id];
636 if (parent->invalidId != createStmtId &&
637 parent->invalidId != lastUseStmtId
639 Lifetime livetime = lastUseStmtId - createStmtId;
641 parent->lifetimes.setLifetime(createStmtId,
id, livetime);
642 }
else if (parent->invalidId == createStmtId && parent->invalidId == lastUseStmtId) {
644 }
else if (parent->invalidId == lastUseStmtId && parent->invalidId != createStmtId) {
646 parent->lifetimes.setLifetime(createStmtId,
id, 0);
648 CODI_EXCEPTION(
"Identifier '%d' is used but not created, this is an error in the tape.", (
int)
id);
651 lastUseStmtId = parent->invalidId;
656 if (
id != parent->passiveId) {
657 idCreatedInStmt[id] = curStmtId;
660 parent->lifetimes.addOutputToStatement(
id);
665 if (
id != parent->passiveId) {
666 idLastUseInStmt[id] = curStmtId;
672 if (
id != parent->passiveId) {
674 idCreatedInStmt[id] = curStmtId;
677 parent->lifetimes.addOutputToStatement(
id);
682 parent->lifetimes.finalizeStatement();
690 idLastUseInStmt[id] = curStmtId + parent->hotLiveTimeThreshold + 1;
696 for (
Lifetime& stmtId : idCreatedInStmt) {
697 if (stmtId != parent->invalidId) {
698 computeLifetime(curId);
699 stmtId = parent->invalidId;
709 struct HandleShift :
public ApplyIdentifierModification<Tape, HandleShift> {
712 IdentifierCacheOptimizerHotCold* parent;
716 CODI_INLINE HandleShift(IdentifierCacheOptimizerHotCold* p)
717 : Base(p->tape), parent(p), coldShift(parent->stats.unused) {}
721 if (0 !=
id && !parent->generatorHot.isHandledByThis(
id)) {
739 stats.totalHot = generatorHot.getGeneratedSize() + 1;
740 stats.totalCold = generatorCold.getGeneratedSize();
741 stats.total = stats.totalHot + stats.totalCold;
742 stats.unused = generatorCold.start - stats.total + 1;
748 template<
typename FuncIn,
typename FuncOut>
752 HandleHotColdAnalysis hotCold = {
this};
755 iterIn([&](Identifier&
id) {
756 hotCold.addProgrammInput(
id);
758 hotCold.applyPostOutputLogic();
761 tape.iterateForward(hotCold);
763 iterOut([&](Identifier&
id) {
764 hotCold.setOutputLifetime(
id);
773 HandleTranslate translate = {
this};
776 translate.applyPostInputLogic();
777 iterIn([&](Identifier&
id) {
778 translate.addProgrammInput(
id);
780 translate.applyPostOutputLogic();
782 tape.iterateForward(translate);
784 iterOut([&](Identifier&
id) {
785 translate.applyToInput(
id);
793 HandleShift shift = {
this};
794 tape.iterateForward(shift);
796 auto doShift = [&](Identifier& id) {
797 shift.applyShift(
id);
806 return stats.total - 1;
810 template<
typename Stream>
812 out <<
"Hot: " << stats.totalHot << std::endl;
813 out <<
"Cold: " << stats.totalCold << std::endl;
814 out <<
"Total: " << stats.total << std::endl;
815 out <<
"Unused: " << stats.unused << std::endl;
819 template<
typename Stream>
821 out <<
"Hot; Cold; Total; Unused;";
825 template<
typename Stream>
827 out <<
"Hot: " << stats.totalHot << std::endl;
828 out <<
"Cold: " << stats.totalCold << std::endl;
829 out <<
"Total: " << stats.total << std::endl;
830 out <<
"Unused: " << stats.unused << std::endl;
#define CODI_NO_INLINE
See codi::Config::AvoidedInlines.
Definition config.h:426
#define CODI_INLINE
See codi::Config::ForcedInlines.
Definition config.h:469
#define codiAssert(x)
See codi::Config::EnableAssert.
Definition config.h:441
#define CODI_DD(Type, Default)
Abbreviation for CODI_DECLARE_DEFAULT.
Definition macros.hpp:97
bool constexpr EnableAssert
Enables asserts in CoDiPack for consistency checking.
Definition config.h:445
uint8_t ArgumentSize
Type for the number of arguments in statements.
Definition config.h:117
bool constexpr isPrimalValueTape
Value entry of IsPrimalValueTape.
Definition tapeTraits.hpp:106
CoDiPack - Code Differentiation Package.
Definition codi.hpp:97
inlinevoid CODI_UNUSED(Args const &...)
Disable unused warnings for an arbitrary number of arguments.
Definition macros.hpp:55
Helper class for iterating or changing the identifiers of a tape.
Definition identifierCacheOptimizer.hpp:66
typename Tape::Real Real
See FullTapeInterface.
Definition identifierCacheOptimizer.hpp:70
inlinevoid handleStatement(EvalHandle const &evalHandle, codi::Config::ArgumentSize const &nPassiveValues, size_t &linearAdjointPosition, char *stmtData)
Definition identifierCacheOptimizer.hpp:147
inlinevoid handleStatement(Identifier &lhsIndex, codi::Config::ArgumentSize const &size, Real const *jacobians, Identifier *rhsIdentifiers)
Definition identifierCacheOptimizer.hpp:128
inlinevoid handleLowLevelFunction(codi::LowLevelFunctionEntry< Tape, Real, Identifier > const &func, codi::ByteDataView &llfData)
Definition identifierCacheOptimizer.hpp:176
T_Tape Tape
See ApplyIdentifierModification.
Definition identifierCacheOptimizer.hpp:67
inlinevoid applyPostOutputLogic()
Called after applyToOutput has been called for all outputs.
Definition identifierCacheOptimizer.hpp:106
inlinevoid applyToInput(Identifier &id)
Called for each input of each statement or low level function.
Definition identifierCacheOptimizer.hpp:89
T_Impl Impl
See ApplyIdentifierModification.
Definition identifierCacheOptimizer.hpp:68
typename Tape::EvalHandle EvalHandle
See FullTapeInterface.
Definition identifierCacheOptimizer.hpp:72
inlinevoid applyPostInputLogic()
Called after applyToInput has been called for all inputs.
Definition identifierCacheOptimizer.hpp:101
ApplyIdentifierModification(Tape &tape)
Constructor.
Definition identifierCacheOptimizer.hpp:82
typename Tape::Identifier Identifier
See FullTapeInterface.
Definition identifierCacheOptimizer.hpp:71
inlinevoid applyToOutput(Identifier &id)
Called for each output of each statement or low level function.
Definition identifierCacheOptimizer.hpp:95
Definition byteDataView.hpp:51
inlinevoid reset()
Reset the data position to the start of the data.
Definition byteDataView.hpp:126
interface for callbacks from an custom tape iteration. See CustomIteratorTapeInterface for details.
Definition customIteratorTapeInterface.hpp:55
T_Identifier Identifier
See ReadWriteTapeInterface.
Definition customIteratorTapeInterface.hpp:58
Reassigns the identifiers in a tape such that the tape evaluation is optimized.
Definition identifierCacheOptimizer.hpp:451
void writeStatsHeader(Stream &out)
Write the header for the statistics to a stream.
Definition identifierCacheOptimizer.hpp:820
T_Tape Tape
See IdentifierCacheOptimizerHotCold.
Definition identifierCacheOptimizer.hpp:453
void writeStatsRow(Stream &out)
Write the data for this optimizer into a row.
Definition identifierCacheOptimizer.hpp:826
void eval(FuncIn &&iterIn, FuncOut &&iterOut)
Perform the tape cache optimization. Se the class description for details.
Definition identifierCacheOptimizer.hpp:749
T_Lifetime Lifetime
See IdentifierCacheOptimizerHotCold.
Definition identifierCacheOptimizer.hpp:454
inlinesize_t getLargestCreatedIndex()
Get the new largest created index.
Definition identifierCacheOptimizer.hpp:805
void writeStatsVerbose(Stream &out)
Write statistics to a stream as a list.
Definition identifierCacheOptimizer.hpp:811
inlinevoid setHotLiveTimeThreshold(Lifetime hotLiveTimeThreshold)
Set the threshold for hot variables. Smaller values will be hot and larger ones cold.
Definition identifierCacheOptimizer.hpp:499
Definition identifierCacheOptimizer.hpp:203
inlinebool isHandledByThis(Identifier id)
Check if the identifier is handled by this generator.
Definition identifierCacheOptimizer.hpp:247
inlinevoid init(Identifier start, UnsignedIdentifier dir)
Initialize the range.
Definition identifierCacheOptimizer.hpp:214
inlineIdentifier generateFresh()
Generate an unused identifier.
Definition identifierCacheOptimizer.hpp:226
inlineIdentifier generate()
Generate an identifier.
Definition identifierCacheOptimizer.hpp:234
UnsignedIdentifier nextDirection
Step for the next generated identifier.
Definition identifierCacheOptimizer.hpp:209
std::set< Identifier > stack
List of all unused identifiers.
Definition identifierCacheOptimizer.hpp:211
Identifier nextFree
Next generated identifier.
Definition identifierCacheOptimizer.hpp:208
Identifier start
Start of the identifier range.
Definition identifierCacheOptimizer.hpp:207
inlinevoid free(Identifier id)
Free an identifier.
Definition identifierCacheOptimizer.hpp:221
inlineIdentifier getGeneratedSize()
Get number of generated identifiers.
Definition identifierCacheOptimizer.hpp:262
Helper class for the lifetime management of the identifiers.
Definition identifierCacheOptimizer.hpp:279
inlinebool isLLFStatement(Lifetime const &stmtId)
Check if the statement has just one output.
Definition identifierCacheOptimizer.hpp:313
inlinevoid finalizeStatement()
Definition identifierCacheOptimizer.hpp:378
inlinevoid setLifetime(Lifetime const &stmtId, Identifier const &outputId, Lifetime const &lifetime)
Set the lifetime for an output of a statement. The statement should already be finalized.
Definition identifierCacheOptimizer.hpp:352
inlinevoid addOutputToStatement(Identifier const &id)
Add an output to the current statement.
Definition identifierCacheOptimizer.hpp:370
inlinevoid prepareStatementRead(Lifetime const &stmtId)
Call before lifetimes are read for a statement.
Definition identifierCacheOptimizer.hpp:318
inlineLifetime getLifetime(Lifetime const &stmtId, Identifier const &outputId)
Get the lifetime of an output of the statement. prepareStatementRead needs to be called first.
Definition identifierCacheOptimizer.hpp:329
Low level function entry on the tape. See LowLevelFunctionTapeInterface for details.
Definition lowLevelFunctionEntry.hpp:69
This class is used during the writing process of a primal value tape. The WriteInfo is returned by St...
Definition tapeReaderWriterInterface.hpp:69
size_t numberOfOutputArguments
Number of output arguments.
Definition tapeReaderWriterInterface.hpp:70