Make the parent-map use significantly less memory.

On test files I ran this on, memory consumption overall went down from
2.5G to 2G, without performance regressions.
I also investigated making DynTypedNode by itself smaller (by pulling
out pointers for everything that doesn't fit in 8 bytes). This led to
another 200-300MB saved, but also introduced a significant regression in
performance due to the memory management overhead.

llvm-svn: 209297
This commit is contained in:
Manuel Klimek 2014-05-21 13:28:59 +00:00
parent 2a958321c8
commit 95403e6f60
2 changed files with 41 additions and 4 deletions

View File

@ -424,7 +424,9 @@ public:
typedef llvm::SmallVector<ast_type_traits::DynTypedNode, 1> ParentVector;
/// \brief Maps from a node to its parents.
typedef llvm::DenseMap<const void *, ParentVector> ParentMap;
typedef llvm::DenseMap<const void *,
llvm::PointerUnion<ast_type_traits::DynTypedNode *,
ParentVector *>> ParentMap;
/// \brief Returns the parents of the given node.
///
@ -2293,6 +2295,7 @@ private:
friend class DeclContext;
friend class DeclarationNameTable;
void ReleaseDeclContextMaps();
void ReleaseParentMapEntries();
std::unique_ptr<ParentMap> AllParents;

View File

@ -755,6 +755,8 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
}
ASTContext::~ASTContext() {
ReleaseParentMapEntries();
// Release the DenseMaps associated with DeclContext objects.
// FIXME: Is this the ideal solution?
ReleaseDeclContextMaps();
@ -789,6 +791,18 @@ ASTContext::~ASTContext() {
llvm::DeleteContainerSeconds(MangleNumberingContexts);
}
void ASTContext::ReleaseParentMapEntries() {
if (!AllParents) return;
for (const auto &Entry : *AllParents) {
if (Entry.second.is<ast_type_traits::DynTypedNode *>()) {
delete Entry.second.get<ast_type_traits::DynTypedNode *>();
} else {
assert(Entry.second.is<ParentVector *>());
delete Entry.second.get<ParentVector *>();
}
}
}
void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) {
Deallocations[Callback].push_back(Data);
}
@ -8162,7 +8176,7 @@ namespace {
bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *)) {
if (!Node)
return true;
if (ParentStack.size() > 0)
if (ParentStack.size() > 0) {
// FIXME: Currently we add the same parent multiple times, for example
// when we visit all subexpressions of template instantiations; this is
// suboptimal, bug benign: the only way to visit those is with
@ -8171,7 +8185,23 @@ namespace {
// map. The main problem there is to implement hash functions /
// comparison operators for all types that DynTypedNode supports that
// do not have pointer identity.
(*Parents)[Node].push_back(ParentStack.back());
auto &NodeOrVector = (*Parents)[Node];
if (NodeOrVector.isNull()) {
NodeOrVector = new ast_type_traits::DynTypedNode(ParentStack.back());
} else if (NodeOrVector
.template is<ast_type_traits::DynTypedNode *>()) {
auto *Node =
NodeOrVector.template get<ast_type_traits::DynTypedNode *>();
auto *Vector = new ASTContext::ParentVector(1, *Node);
Vector->push_back(ParentStack.back());
NodeOrVector = Vector;
delete Node;
} else {
assert(NodeOrVector.template is<ASTContext::ParentVector *>());
NodeOrVector.template get<ASTContext::ParentVector *>()->push_back(
ParentStack.back());
}
}
ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));
bool Result = (this ->* traverse) (Node);
ParentStack.pop_back();
@ -8209,7 +8239,11 @@ ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) {
if (I == AllParents->end()) {
return ParentVector();
}
return I->second;
if (I->second.is<ast_type_traits::DynTypedNode *>()) {
return ParentVector(1, *I->second.get<ast_type_traits::DynTypedNode *>());
}
const auto &Parents = *I->second.get<ParentVector *>();
return ParentVector(Parents.begin(), Parents.end());
}
bool