From 6f7b95e50bed046c9533dbe81483f853bbbf0b8c Mon Sep 17 00:00:00 2001 From: Benjamin Segovia Date: Fri, 16 Mar 2012 19:26:45 +0000 Subject: [PATCH] Kept on implementing full function DAG Added a monitor for the memory consumption --- backend/src/ir/liveness.cpp | 6 +- backend/src/ir/liveness.hpp | 46 ++++++---- backend/src/ir/value.cpp | 203 ++++++++++++++++++++++++++++++++------------ backend/src/ir/value.hpp | 66 +++++++------- backend/src/sys/alloc.cpp | 15 ++++ 5 files changed, 228 insertions(+), 108 deletions(-) diff --git a/backend/src/ir/liveness.cpp b/backend/src/ir/liveness.cpp index 0b9b560..8e5b9ec 100644 --- a/backend/src/ir/liveness.cpp +++ b/backend/src/ir/liveness.cpp @@ -69,7 +69,7 @@ namespace ir { void Liveness::computeLiveOut(void) { // First insert the UEVar from the successors - forEachSuccessor([](BlockInfo &info, const BlockInfo &succ) { + foreach([](BlockInfo &info, const BlockInfo &succ) { const UEVar &ueVarSet = succ.upwardUsed; // Iterate over all the registers in the UEVar of our successor for (auto ueVar = ueVarSet.begin(); ueVar != ueVarSet.end(); ++ueVar) @@ -79,7 +79,7 @@ namespace ir { bool changed = true; while (changed) { changed = false; - forEachSuccessor([&changed](BlockInfo &info, const BlockInfo &succ) { + foreach([&changed](BlockInfo &info, const BlockInfo &succ) { const UEVar &killSet = succ.varKill; const LiveOut &liveOut = succ.liveOut; // Iterate over all the registers in the UEVar of our successor @@ -247,7 +247,7 @@ namespace ir { // Print liveness in each block fn.foreachBlock([&out, &liveness] (const BasicBlock &bb) { - const Liveness::Info &info = liveness.getLiveness(); + const Liveness::Info &info = liveness.getLivenessInfo(); auto it = info.find(&bb); GBE_ASSERT(it != info.end()); printBlock(out, *it->second); diff --git a/backend/src/ir/liveness.hpp b/backend/src/ir/liveness.hpp index ba34d89..6d97b1c 100644 --- a/backend/src/ir/liveness.hpp +++ b/backend/src/ir/liveness.hpp @@ -35,6 +35,14 @@ namespace ir { // Liveness is computed per function class Function; + /*! To choose the iteration direction, we either look at predecessors or + * successors + */ + enum DataFlowDirection { + DF_PRED = 0, + DF_SUCC = 1 + }; + /*! Compute liveness of each register */ class Liveness : public NonCopyable { @@ -67,7 +75,7 @@ namespace ir { /*! Gives for each block the variables alive at entry / exit */ typedef map Info; /*! Return the complete liveness info */ - INLINE const Info &getLiveness(void) const { return liveness; } + INLINE const Info &getLivenessInfo(void) const { return liveness; } /*! Return the complete block info */ INLINE const BlockInfo &getBlockInfo(const BasicBlock &bb) const { auto it = liveness.find(&bb); @@ -76,33 +84,37 @@ namespace ir { } /*! Return the function the liveness was computed on */ INLINE const Function &getFunction(void) const { return fn; } - private: - /*! Store the liveness of all blocks */ - Info liveness; - /*! Compute the liveness for this function */ - Function &fn; - /*! Initialize UEVar and VarKill per block */ - void initBlock(const BasicBlock &bb); - /*! Initialize UEVar and VarKill per instruction */ - void initInstruction(BlockInfo &info, const Instruction &insn); - /*! Now really compute LiveOut based on UEVar and VarKill */ - void computeLiveOut(void); - /*! Actually do something for each successor of *all* blocks */ - template - void forEachSuccessor(const T &functor) { + /*! Actually do something for each successor / predecessor of *all* blocks */ + template + void foreach(const T &functor) { // Iterate on all blocks for (auto it = liveness.begin(); it != liveness.end(); ++it) { BlockInfo &info = *it->second; const BasicBlock &bb = info.bb; - const BlockSet set = bb.getSuccessorSet(); + const BlockSet *set = NULL; + if (dir == DF_SUCC) + set = &bb.getSuccessorSet(); + else + set = &bb.getPredecessorSet(); // Iterate over all successors - for (auto other = set.begin(); other != set.end(); ++other) { + for (auto other = set->begin(); other != set->end(); ++other) { auto otherInfo = liveness.find(*other); GBE_ASSERT(otherInfo != liveness.end() && otherInfo->second != NULL); functor(info, *otherInfo->second); } } } + private: + /*! Store the liveness of all blocks */ + Info liveness; + /*! Compute the liveness for this function */ + Function &fn; + /*! Initialize UEVar and VarKill per block */ + void initBlock(const BasicBlock &bb); + /*! Initialize UEVar and VarKill per instruction */ + void initInstruction(BlockInfo &info, const Instruction &insn); + /*! Now really compute LiveOut based on UEVar and VarKill */ + void computeLiveOut(void); }; /*! Output a nice ASCII reprensation of the liveness */ diff --git a/backend/src/ir/value.cpp b/backend/src/ir/value.cpp index 8d0cb1e..4de5c40 100644 --- a/backend/src/ir/value.cpp +++ b/backend/src/ir/value.cpp @@ -40,7 +40,7 @@ namespace ir { class LiveOutSet { public: - LiveOutSet(const Liveness &liveness, const FunctionDAG &dag); + LiveOutSet(Liveness &liveness, const FunctionDAG &dag); ~LiveOutSet(void); /*! One set per register */ typedef set RegDefSet; @@ -48,19 +48,44 @@ namespace ir { typedef map BlockDefMap; /*! All the block definitions map in the functions */ typedef map FunctionDefMap; - FunctionDefMap defMap; //!< All per-block data - const Liveness &liveness; //!< Contains LiveOut information - const FunctionDAG &dag; //!< Structure we are building + /*! Performs the double look-up to get the set of defs per register */ + RegDefSet &getDefSet(const BasicBlock *bb, const Register ®) { + auto bbIt = defMap.find(bb); + GBE_ASSERT(bbIt != defMap.end()); + auto defIt = bbIt->second->find(reg); + GBE_ASSERT(defIt != bbIt->second->end() && defIt->second != NULL); + return *defIt->second; + } + /*! Build a UD-chain as the union of the predecessor chains */ + void fillUDChain(UDChain &udChain, const BasicBlock &bb, const Register ®); + /*! Fast per register definition set allocation */ DECL_POOL(RegDefSet, regDefSetPool); + /*! Fast register sets allocation */ DECL_POOL(BlockDefMap, blockDefMapPool); + FunctionDefMap defMap; //!< All per-block data + Liveness &liveness; //!< Contains LiveOut information + const FunctionDAG &dag; //!< Structure we are building + private: + /*! Initialize liveOut with the instruction destination values */ + void initializeInstructionDst(void); + /*! Initialize liveOut with the function argument */ + void initializeFunctionInput(void); + /*! Iterate to completely transfer the liveness and get the def sets */ + void iterateLiveOut(void); }; - LiveOutSet::LiveOutSet(const Liveness &liveness, const FunctionDAG &dag) : + LiveOutSet::LiveOutSet(Liveness &liveness, const FunctionDAG &dag) : liveness(liveness), dag(dag) { + this->initializeInstructionDst(); + this->initializeFunctionInput(); + this->iterateLiveOut(); + } + + void LiveOutSet::initializeInstructionDst(void) { const Function &fn = liveness.getFunction(); - // Iterate over each block + // Iterate over each block and initialize the liveOut data fn.foreachBlock([&](const BasicBlock &bb) { GBE_ASSERT(defMap.find(&bb) == defMap.end()); @@ -85,17 +110,98 @@ namespace ir { for (uint32_t dstID = 0; dstID < dstNum; ++dstID) { const Register reg = insn.getDstIndex(fn, dstID); // We only take the most recent definition - if (defined.contains(reg) == false) continue; + if (defined.contains(reg) == true) continue; // Not in LiveOut, so does not matter if (info.inLiveOut(reg) == false) continue; + defined.insert(reg); // Insert the outgoing definition for this register auto regDefSet = blockDefMap->find(reg); - const ValueDef *def = this->dag.getDefAddress(insn, dstID); + const ValueDef *def = this->dag.getDefAddress(&insn, dstID); GBE_ASSERT(regDefSet != blockDefMap->end() && def != NULL); + // May be NULL if there is no definition regDefSet->second->insert(def); } }); }); + + // The first block must also transfer the function arguments + const BasicBlock &top = fn.getBlock(0); + auto info = this->liveness.getBlockInfo(top); + auto blockDefMapIt = defMap.find(&top); + GBE_ASSERT(blockDefMapIt != defMap.end()); + auto blockDefMap = blockDefMapIt->second; + const uint32_t inputNum = fn.inputNum(); + for (uint32_t inputID = 0; inputID < inputNum; ++inputID) { + const FunctionInput &input = fn.getInput(inputID); + const Register reg = input.reg; + // Do not transfer dead values + if (info.inLiveOut(reg) == false) continue; + // If we overwrite it, do not transfer the initial value + if (info.inVarKill(reg) == false) continue; + const ValueDef *def = this->dag.getDefAddress(&input); + GBE_ASSERT(blockDefMap->contains(reg) == false); + auto regDefSet = this->newRegDefSet(); + regDefSet->insert(def); + blockDefMap->insert(std::make_pair(reg, regDefSet)); + } + } + + void LiveOutSet::initializeFunctionInput(void) { + const Function &fn = liveness.getFunction(); + const uint32_t inputNum = fn.inputNum(); + + // The first block must also transfer the function arguments + const BasicBlock &top = fn.getBlock(0); + const Liveness::BlockInfo &info = this->liveness.getBlockInfo(top); + GBE_ASSERT(defMap.contains(&top) == true); + auto blockDefMap = defMap.find(&top)->second; + + // Insert all the values that are not overwritten in the block and alive at + // the end of it + for (uint32_t inputID = 0; inputID < inputNum; ++inputID) { + const FunctionInput &input = fn.getInput(inputID); + const Register reg = input.reg; + // Do not transfer dead values + if (info.inLiveOut(reg) == false) continue; + // If we overwrite it, do not transfer the initial value + if (info.inVarKill(reg) == false) continue; + const ValueDef *def = this->dag.getDefAddress(&input); + GBE_ASSERT(blockDefMap->contains(reg) == false); + auto regDefSet = this->newRegDefSet(); + regDefSet->insert(def); + blockDefMap->insert(std::make_pair(reg, regDefSet)); + } + } + + void LiveOutSet::iterateLiveOut(void) { + bool changed = true; + + while (changed) { + changed = false; + + // Compute the union of the current liveout definitions with the previous + // ones. Do not take into account the killed values though + liveness.foreach([&](Liveness::BlockInfo &curr, + const Liveness::BlockInfo &pred) + { + const BasicBlock &bb = curr.bb; + const BasicBlock &pbb = pred.bb; + for (auto it = curr.liveOut.begin(); it != curr.liveOut.end(); ++it) { + const Register reg = *it; + if (pred.inLiveOut(reg) == false) continue; + if (curr.inVarKill(reg) == true) continue; + RegDefSet &currSet = this->getDefSet(&bb, reg); + RegDefSet &predSet = this->getDefSet(&pbb, reg); + + // Transfer the values + for (auto it = predSet.begin(); it != predSet.end(); ++it) { + if (currSet.contains(*it)) continue; + changed = true; + currSet.insert(*it); + } + } + }); + } } LiveOutSet::~LiveOutSet(void) { @@ -107,26 +213,27 @@ namespace ir { } } - FunctionDAG::FunctionDAG(const Liveness &liveness) { + FunctionDAG::FunctionDAG(Liveness &liveness) { const Function &fn = liveness.getFunction(); - LiveOutSet p(liveness, *this); + // We first start with empty chains - udEmpty = this->newUDChain(); udEmpty->second = NULL; - duEmpty = this->newDUChain(); duEmpty->second = NULL; + udEmpty = this->newUDChain(); + duEmpty = this->newDUChain(); // First create the chains and insert them in their respective maps fn.foreachInstruction([this, udEmpty, duEmpty](const Instruction &insn) { - // sources == value uses const uint32_t srcNum = insn.getSrcNum(); for (uint32_t srcID = 0; srcID < srcNum; ++srcID) { - ValueUse *valueUse = this->newValueUse(insn, srcID); + ValueUse *valueUse = this->newValueUse(&insn, srcID); + useName.insert(std::make_pair(*valueUse, valueUse)); udGraph.insert(std::make_pair(*valueUse, udEmpty)); } // destinations == value defs const uint32_t dstNum = insn.getDstNum(); for (uint32_t dstID = 0; dstID < dstNum; ++dstID) { - ValueDef *valueDef = this->newValueDef(insn, dstID); + ValueDef *valueDef = this->newValueDef(&insn, dstID); + defName.insert(std::make_pair(*valueDef, valueDef)); duGraph.insert(std::make_pair(*valueDef, duEmpty)); } }); @@ -135,9 +242,13 @@ namespace ir { const uint32_t inputNum = fn.inputNum(); for (uint32_t inputID = 0; inputID < inputNum; ++inputID) { const FunctionInput &input = fn.getInput(inputID); - ValueDef *valueDef = this->newValueDef(input); + ValueDef *valueDef = this->newValueDef(&input); + defName.insert(std::make_pair(*valueDef, valueDef)); duGraph.insert(std::make_pair(*valueDef, duEmpty)); } + + // We create the liveOutSet to help us transfer the definitions + const LiveOutSet liveOutSet(liveness, *this); } /*! Helper to deallocate objects */ @@ -155,76 +266,64 @@ namespace ir { set destroyed; // Release the empty ud-chains and du-chains - PTR_RELEASE(ValueUse, udEmpty->second); - PTR_RELEASE(ValueDef, duEmpty->second); PTR_RELEASE(UDChain, udEmpty); PTR_RELEASE(DUChain, duEmpty); // We free all the ud-chains for (auto it = udGraph.begin(); it != udGraph.end(); ++it) { - auto udChain = it->second; - auto defs = udChain->first; - for (auto def = defs.begin(); def != defs.end(); ++def) + auto defs = it->second; + for (auto def = defs->begin(); def != defs->end(); ++def) PTR_RELEASE(ValueDef, *def); - PTR_RELEASE(ValueUse, udChain->second); - PTR_RELEASE(UDChain, udChain); + PTR_RELEASE(UDChain, defs); } // We free all the du-chains for (auto it = duGraph.begin(); it != duGraph.end(); ++it) { - auto duChain = it->second; - auto uses = duChain->first; - for (auto use = uses.begin(); use != uses.end(); ++use) + auto uses = it->second; + for (auto use = uses->begin(); use != uses->end(); ++use) PTR_RELEASE(ValueUse, *use); - PTR_RELEASE(ValueDef, duChain->second); - PTR_RELEASE(DUChain, duChain); + PTR_RELEASE(DUChain, uses); } } #undef PTR_RELEASE - const DUChain &FunctionDAG::getDUChain(const Instruction &insn, uint32_t dstID) const { + const DUChain &FunctionDAG::getUse(const Instruction *insn, uint32_t dstID) const { const ValueDef def(insn, dstID); auto it = duGraph.find(def); GBE_ASSERT(it != duGraph.end()); return *it->second; } - const DUChain &FunctionDAG::getDUChain(const FunctionInput &input) const { + const DUChain &FunctionDAG::getUse(const FunctionInput *input) const { const ValueDef def(input); auto it = duGraph.find(def); GBE_ASSERT(it != duGraph.end()); return *it->second; } - const UDChain &FunctionDAG::getUDChain(const Instruction &insn, uint32_t srcID) const { + const UDChain &FunctionDAG::getDef(const Instruction *insn, uint32_t srcID) const { const ValueUse use(insn, srcID); auto it = udGraph.find(use); GBE_ASSERT(it != udGraph.end()); return *it->second; } - const ValueUseSet &FunctionDAG::getUse(const Instruction &insn, uint32_t dstID) const { - const DUChain &chain = this->getDUChain(insn, dstID); - return chain.first; - } - const ValueUseSet &FunctionDAG::getUse(const FunctionInput &input) const { - const DUChain &chain = this->getDUChain(input); - return chain.first; - } - const ValueDefSet &FunctionDAG::getDef(const Instruction &insn, uint32_t srcID) const { - const UDChain &chain = this->getUDChain(insn, srcID); - return chain.first; - } - const ValueDef *FunctionDAG::getDefAddress(const Instruction &insn, uint32_t dstID) const { - const DUChain &chain = this->getDUChain(insn, dstID); - return chain.second; + const ValueDef *FunctionDAG::getDefAddress(const Instruction *insn, uint32_t dstID) const { + const ValueDef def(insn, dstID); + auto it = defName.find(def); + GBE_ASSERT(it != defName.end() && it->second != NULL); + return it->second; } - const ValueDef *FunctionDAG::getDefAddress(const FunctionInput &input) const { - const DUChain &chain = this->getDUChain(input); - return chain.second; + const ValueDef *FunctionDAG::getDefAddress(const FunctionInput *input) const { + const ValueDef def(input); + auto it = defName.find(def); + GBE_ASSERT(it != defName.end() && it->second != NULL); + return it->second; } - const ValueUse *FunctionDAG::getUseAddress(const Instruction &insn, uint32_t srcID) const { - const UDChain &chain = this->getUDChain(insn, srcID); - return chain.second; + const ValueUse *FunctionDAG::getUseAddress(const Instruction *insn, uint32_t srcID) const { + const ValueUse use(insn, srcID); + auto it = useName.find(use); + GBE_ASSERT(it != useName.end() && it->second != NULL); + return it->second; } } /* namespace ir */ } /* namespace gbe */ diff --git a/backend/src/ir/value.hpp b/backend/src/ir/value.hpp index 3704b26..9b3ec63 100644 --- a/backend/src/ir/value.hpp +++ b/backend/src/ir/value.hpp @@ -48,22 +48,22 @@ namespace ir { INSTRUCTION_DST = 1 }; /*! Build a value from an instruction destination */ - ValueDef(const Instruction &insn, uint32_t dstID = 0u) : + ValueDef(const Instruction *insn, uint32_t dstID = 0u) : type(INSTRUCTION_DST) { - this->data.insn = &insn; + this->data.insn = insn; this->data.dstID = dstID; } /*! Build a value from a function argument */ - ValueDef(const FunctionInput &input) : type(FUNCTION_INPUT) { - this->data.input = &input; + ValueDef(const FunctionInput *input) : type(FUNCTION_INPUT) { + this->data.input = input; } /*! Get the type of the value */ INLINE Type getType(void) const { return type; } /*! Get the instruction (only if this is a instruction value) */ - INLINE const Instruction &getInstruction(void) const { + INLINE const Instruction *getInstruction(void) const { GBE_ASSERT(type == INSTRUCTION_DST); - return *data.insn; + return data.insn; } /*! Get the destination ID (only if this is a instruction value) */ INLINE uint32_t getDstID(void) const { @@ -71,9 +71,9 @@ namespace ir { return data.dstID; } /*! Get the function input (only if this is a function argument) */ - INLINE const FunctionInput &getFunctionInput(void) const { + INLINE const FunctionInput *getFunctionInput(void) const { GBE_ASSERT(type == FUNCTION_INPUT); - return *data.input; + return data.input; } private: @@ -97,12 +97,12 @@ namespace ir { const ValueDef::Type type1 = def1.getType(); if (type0 != type1) return uint32_t(type0) < uint32_t(type1); if (type0 == ValueDef::FUNCTION_INPUT) { - const FunctionInput *in0 = &def0.getFunctionInput(); - const FunctionInput *in1 = &def1.getFunctionInput(); + const FunctionInput *in0 = def0.getFunctionInput(); + const FunctionInput *in1 = def1.getFunctionInput(); return uintptr_t(in0) < uintptr_t(in1); } else { - const Instruction *insn0 = &def0.getInstruction(); - const Instruction *insn1 = &def1.getInstruction(); + const Instruction *insn0 = def0.getInstruction(); + const Instruction *insn1 = def1.getInstruction(); if (insn0 != insn1) return uintptr_t(insn0) < uintptr_t(insn1); const uint32_t dst0 = def0.getDstID(); const uint32_t dst1 = def1.getDstID(); @@ -117,10 +117,10 @@ namespace ir { { public: /*! Build a value use */ - ValueUse(const Instruction &insn, uint32_t srcID = 0u) : - insn(&insn), srcID(srcID) {} + ValueUse(const Instruction *insn, uint32_t srcID = 0u) : + insn(insn), srcID(srcID) {} /*! Get the instruction of the use */ - const Instruction &getInstruction(void) const { return *insn; } + const Instruction *getInstruction(void) const { return insn; } /*! Get the source index for this use */ uint32_t getSrcID(void) const { return srcID; } private: @@ -130,8 +130,8 @@ namespace ir { /*! Compare two value uses (used in maps) */ INLINE bool operator< (const ValueUse &use0, const ValueUse &use1) { - const Instruction *insn0 = &use0.getInstruction(); - const Instruction *insn1 = &use1.getInstruction(); + const Instruction *insn0 = use0.getInstruction(); + const Instruction *insn1 = use1.getInstruction(); if (insn0 != insn1) return uintptr_t(insn0) < uintptr_t(insn1); const uint32_t src0 = use0.getSrcID(); const uint32_t src1 = use1.getSrcID(); @@ -139,38 +139,30 @@ namespace ir { } /*! All uses of a definition */ - typedef set ValueUseSet; - typedef std::pair DUChain; + typedef set DUChain; /*! All possible definitions for a use */ - typedef set ValueDefSet; - typedef std::pair UDChain; + typedef set UDChain; /*! Get the chains (in both directions) for the complete program */ class FunctionDAG { public: /*! Build the complete DU/UD graphs for the program included in liveness */ - FunctionDAG(const Liveness &liveness); + FunctionDAG(Liveness &liveness); /*! Free all the resources */ ~FunctionDAG(void); /*! Get the du-chain for the given instruction and destination */ - const DUChain &getDUChain(const Instruction &insn, uint32_t dstID) const; + const DUChain &getUse(const Instruction *insn, uint32_t dstID) const; /*! Get the du-chain for the given function input */ - const DUChain &getDUChain(const FunctionInput &input) const; + const DUChain &getUse(const FunctionInput *input) const; /*! Get the ud-chain for the instruction and source */ - const UDChain &getUDChain(const Instruction &insn, uint32_t srcID) const; - /*! Get the use set for the given definition */ - const ValueUseSet &getUse(const Instruction &insn, uint32_t dstID) const; - /*! Get the use set for the function argument */ - const ValueUseSet &getUse(const FunctionInput &input) const; - /*! Get the definition set for the given source */ - const ValueDefSet &getDef(const Instruction &insn, uint32_t srcID) const; + const UDChain &getDef(const Instruction *insn, uint32_t srcID) const; /*! Get the pointer to the definition *as stored in the DAG* */ - const ValueDef *getDefAddress(const Instruction &insn, uint32_t dstID) const; + const ValueDef *getDefAddress(const Instruction *insn, uint32_t dstID) const; /*! Get the pointer to the definition *as stored in the DAG* */ - const ValueDef *getDefAddress(const FunctionInput &input) const; + const ValueDef *getDefAddress(const FunctionInput *input) const; /*! Get the pointer to the use *as stored in the DAG* */ - const ValueUse *getUseAddress(const Instruction &insn, uint32_t srcID) const; + const ValueUse *getUseAddress(const Instruction *insn, uint32_t srcID) const; /*! The UDChain for each definition use */ typedef map UDGraph; /*! The DUChain for each definition */ @@ -178,8 +170,10 @@ namespace ir { private: UDGraph udGraph; //!< All the UD chains DUGraph duGraph; //!< All the DU chains - UDChain *udEmpty; //!< For all empty ud chains - DUChain *duEmpty; //!< For all empty du chains + UDChain *udEmpty; //!< Void use set + DUChain *duEmpty; //!< Void def set + map useName; //!< Get the ValueUse pointer from the value + map defName; //!< Get the ValueDef pointer from the value DECL_POOL(ValueDef, valueDefPool); //!< Fast ValueDef allocation DECL_POOL(ValueUse, valueUsePool); //!< Fast ValueUse allocation DECL_POOL(UDChain, udChainPool); //!< Fast UDChain allocation diff --git a/backend/src/sys/alloc.cpp b/backend/src/sys/alloc.cpp index af4d390..c7305c2 100644 --- a/backend/src/sys/alloc.cpp +++ b/backend/src/sys/alloc.cpp @@ -42,6 +42,7 @@ #endif /* __ICC__ */ #include #include +#include //////////////////////////////////////////////////////////////////////////////// /// Memory debugger @@ -139,10 +140,18 @@ namespace gbe /*! Declare C like interface functions here */ static MemDebugger *memDebugger = NULL; + /*! Monitor maximum memory requirement in the compiler */ + static size_t memDebuggerCurrSize = 0; + static size_t memDebuggerMaxSize = 0; + /*! Stop the memory debugger */ static void MemDebuggerEnd(void) { MemDebugger *_debug = memDebugger; memDebugger = NULL; + GBE_ASSERT(memDebuggerCurrSize == 0); + std::cout << "Maximum memory consumption: " + << std::setprecision(2) << std::fixed + << float(memDebuggerMaxSize) / 1024. << "KB" << std::endl; delete _debug; } @@ -192,6 +201,8 @@ namespace gbe void *ptr = std::malloc(size + sizeof(size_t)); *(size_t *) ptr = size; MemDebuggerInitializeMem((char*) ptr + sizeof(size_t), size); + memDebuggerCurrSize += size; + memDebuggerMaxSize = std::max(memDebuggerCurrSize, memDebuggerMaxSize); return (char *) ptr + sizeof(size_t); } void memFree(void *ptr) { @@ -199,6 +210,7 @@ namespace gbe char *toFree = (char*) ptr - sizeof(size_t); const size_t size = *(size_t *) toFree; MemDebuggerInitializeMem(ptr, size); + memDebuggerCurrSize -= size; std::free(toFree); } } @@ -221,6 +233,8 @@ namespace gbe ((void**)aligned)[-1] = mem; ((uintptr_t*)aligned)[-2] = uintptr_t(size); MemDebuggerInitializeMem(aligned, size); + memDebuggerCurrSize += size; + memDebuggerMaxSize = std::max(memDebuggerCurrSize, memDebuggerMaxSize); return aligned; } @@ -229,6 +243,7 @@ namespace gbe const size_t size = ((uintptr_t*)ptr)[-2]; MemDebuggerInitializeMem(ptr, size); free(((void**)ptr)[-1]); + memDebuggerCurrSize -= size; } } } /* namespace gbe */ -- 2.7.4