Eliminate memory allocation from most invocations of

ModuleManager::visit() by keeping a free list of the two data
structures used to store state (a preallocated stack and a visitation
number vector). Improves -fsyntax-only performance for my modules test
case by 2.8%. Modules has pulled ahead by almost 10% with the global
module index.

llvm-svn: 173692
This commit is contained in:
Douglas Gregor 2013-01-28 16:46:33 +00:00
parent 1258519674
commit e97cd90a67
2 changed files with 73 additions and 14 deletions

View File

@ -43,7 +43,7 @@ class ModuleManager {
/// \brief The visitation order.
SmallVector<ModuleFile *, 4> VisitOrder;
/// \brief The list of module files that both we and the global module index
/// know about.
///
@ -63,6 +63,40 @@ class ModuleManager {
/// \brief Update the set of modules files we know about known to the global index.
void updateModulesInCommonWithGlobalIndex();
/// \brief State used by the "visit" operation to avoid malloc traffic in
/// calls to visit().
struct VisitState {
explicit VisitState(unsigned N)
: VisitNumber(N, 0), NextVisitNumber(1), NextState(0)
{
Stack.reserve(N);
}
~VisitState() {
delete NextState;
}
/// \brief The stack used when marking the imports of a particular module
/// as not-to-be-visited.
SmallVector<ModuleFile *, 4> Stack;
/// \brief The visit number of each module file, which indicates when
/// this module file was last visited.
SmallVector<unsigned, 4> VisitNumber;
/// \brief The next visit number to use to mark visited module files.
unsigned NextVisitNumber;
/// \brief The next visit state.
VisitState *NextState;
};
/// \brief The first visit() state in the chain.
VisitState *FirstVisitState;
VisitState *allocateVisitState();
void returnVisitState(VisitState *State);
public:
typedef SmallVector<ModuleFile*, 2>::iterator ModuleIterator;
typedef SmallVector<ModuleFile*, 2>::const_iterator ModuleConstIterator;

View File

@ -162,17 +162,37 @@ void ModuleManager::updateModulesInCommonWithGlobalIndex() {
}
}
ModuleManager::VisitState *ModuleManager::allocateVisitState() {
// Fast path: if we have a cached state, use it.
if (FirstVisitState) {
VisitState *Result = FirstVisitState;
FirstVisitState = FirstVisitState->NextState;
Result->NextState = 0;
return Result;
}
// Allocate and return a new state.
return new VisitState(size());
}
void ModuleManager::returnVisitState(VisitState *State) {
assert(State->NextState == 0 && "Visited state is in list?");
State->NextState = FirstVisitState;
FirstVisitState = State;
}
void ModuleManager::setGlobalIndex(GlobalModuleIndex *Index) {
GlobalIndex = Index;
updateModulesInCommonWithGlobalIndex();
}
ModuleManager::ModuleManager(FileManager &FileMgr)
: FileMgr(FileMgr), GlobalIndex() { }
: FileMgr(FileMgr), GlobalIndex(), FirstVisitState(0) { }
ModuleManager::~ModuleManager() {
for (unsigned i = 0, e = Chain.size(); i != e; ++i)
delete Chain[e - i - 1];
delete FirstVisitState;
}
void
@ -230,10 +250,13 @@ ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
// global module index, since modules could have been added to the module
// manager since we loaded the global module index.
updateModulesInCommonWithGlobalIndex();
delete FirstVisitState;
FirstVisitState = 0;
}
SmallVector<ModuleFile *, 4> Stack;
SmallVector<bool, 4> Visited(size(), false);
VisitState *State = allocateVisitState();
unsigned VisitNumber = State->NextVisitNumber++;
// If the caller has provided us with a hit-set that came from the global
// module index, mark every module file in common with the global module
@ -243,18 +266,19 @@ ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
{
ModuleFile *M = ModulesInCommonWithGlobalIndex[I];
if (!ModuleFilesHit->count(M->File))
Visited[M->Index] = true;
State->VisitNumber[M->Index] = VisitNumber;
}
}
for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
ModuleFile *CurrentModule = VisitOrder[I];
// Should we skip this module file?
if (Visited[CurrentModule->Index])
if (State->VisitNumber[CurrentModule->Index] == VisitNumber)
continue;
// Visit the module.
Visited[CurrentModule->Index] = true;
assert(State->VisitNumber[CurrentModule->Index] == VisitNumber - 1);
State->VisitNumber[CurrentModule->Index] = VisitNumber;
if (!Visitor(*CurrentModule, UserData))
continue;
@ -262,7 +286,6 @@ ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
// module that the current module depends on. To indicate this
// behavior, we mark all of the reachable modules as having been visited.
ModuleFile *NextModule = CurrentModule;
Stack.reserve(size());
do {
// For any module that this module depends on, push it on the
// stack (if it hasn't already been marked as visited).
@ -270,20 +293,22 @@ ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
M = NextModule->Imports.begin(),
MEnd = NextModule->Imports.end();
M != MEnd; ++M) {
if (!Visited[(*M)->Index]) {
Stack.push_back(*M);
Visited[(*M)->Index] = true;
if (State->VisitNumber[(*M)->Index] != VisitNumber) {
State->Stack.push_back(*M);
State->VisitNumber[(*M)->Index] = VisitNumber;
}
}
if (Stack.empty())
if (State->Stack.empty())
break;
// Pop the next module off the stack.
NextModule = Stack.back();
Stack.pop_back();
NextModule = State->Stack.back();
State->Stack.pop_back();
} while (true);
}
returnVisitState(State);
}
/// \brief Perform a depth-first visit of the current module.