Optimize ModuleManager::visit() by precomputing the visitation order

and limiting ourselves to two memory allocations. 10% speedup in
-fsyntax-only time for modules.

With this change, we can actually see some performance different from
the global module index, but it's still about 1%.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@173512 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2013-01-25 22:25:23 +00:00
Родитель 3d115cfd1b
Коммит d07865b42d
2 изменённых файлов: 86 добавлений и 66 удалений

Просмотреть файл

@ -38,7 +38,10 @@ class ModuleManager {
/// \brief A lookup of in-memory (virtual file) buffers
llvm::DenseMap<const FileEntry *, llvm::MemoryBuffer *> InMemoryBuffers;
/// \brief The visitation order.
SmallVector<ModuleFile *, 4> VisitOrder;
public:
typedef SmallVector<ModuleFile*, 2>::iterator ModuleIterator;
typedef SmallVector<ModuleFile*, 2>::const_iterator ModuleConstIterator;

Просмотреть файл

@ -149,77 +149,94 @@ ModuleManager::~ModuleManager() {
void ModuleManager::visit(bool (*Visitor)(ModuleFile &M, void *UserData),
void *UserData) {
unsigned N = size();
// Record the number of incoming edges for each module. When we
// encounter a module with no incoming edges, push it into the queue
// to seed the queue.
SmallVector<ModuleFile *, 4> Queue;
Queue.reserve(N);
llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
UnusedIncomingEdges.reserve(size());
for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) {
if (unsigned Size = (*M)->ImportedBy.size())
UnusedIncomingEdges.push_back(Size);
else {
UnusedIncomingEdges.push_back(0);
Queue.push_back(*M);
// If the visitation number array is the wrong size, resize it and recompute
// an order.
if (VisitOrder.size() != Chain.size()) {
unsigned N = size();
VisitOrder.clear();
VisitOrder.reserve(N);
// Record the number of incoming edges for each module. When we
// encounter a module with no incoming edges, push it into the queue
// to seed the queue.
SmallVector<ModuleFile *, 4> Queue;
Queue.reserve(N);
llvm::SmallVector<unsigned, 4> UnusedIncomingEdges;
UnusedIncomingEdges.reserve(size());
for (ModuleIterator M = begin(), MEnd = end(); M != MEnd; ++M) {
if (unsigned Size = (*M)->ImportedBy.size())
UnusedIncomingEdges.push_back(Size);
else {
UnusedIncomingEdges.push_back(0);
Queue.push_back(*M);
}
}
// Traverse the graph, making sure to visit a module before visiting any
// of its dependencies.
unsigned QueueStart = 0;
while (QueueStart < Queue.size()) {
ModuleFile *CurrentModule = Queue[QueueStart++];
VisitOrder.push_back(CurrentModule);
// For any module that this module depends on, push it on the
// stack (if it hasn't already been marked as visited).
for (llvm::SetVector<ModuleFile *>::iterator
M = CurrentModule->Imports.begin(),
MEnd = CurrentModule->Imports.end();
M != MEnd; ++M) {
// Remove our current module as an impediment to visiting the
// module we depend on. If we were the last unvisited module
// that depends on this particular module, push it into the
// queue to be visited.
unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index];
if (NumUnusedEdges && (--NumUnusedEdges == 0))
Queue.push_back(*M);
}
}
assert(VisitOrder.size() == N && "Visitation order is wrong?");
}
llvm::SmallVector<bool, 4> Skipped(size(), false);
unsigned QueueStart = 0;
while (QueueStart < Queue.size()) {
ModuleFile *CurrentModule = Queue[QueueStart++];
// Check whether this module should be skipped.
if (Skipped[CurrentModule->Index])
SmallVector<ModuleFile *, 4> Stack;
SmallVector<bool, 4> Visited(size(), false);
for (unsigned I = 0, N = VisitOrder.size(); I != N; ++I) {
ModuleFile *CurrentModule = VisitOrder[I];
// Should we skip this module file?
if (Visited[CurrentModule->Index])
continue;
Skipped[CurrentModule->Index] = true;
if (Visitor(*CurrentModule, UserData)) {
// The visitor has requested that cut off visitation of any
// module that the current module depends on. To indicate this
// behavior, we mark all of the reachable modules as "skipped".
SmallVector<ModuleFile *, 4> Stack;
Stack.push_back(CurrentModule);
Skipped[CurrentModule->Index] = true;
while (!Stack.empty()) {
ModuleFile *NextModule = Stack.back();
Stack.pop_back();
// For any module that this module depends on, push it on the
// stack (if it hasn't already been marked as visited).
for (llvm::SetVector<ModuleFile *>::iterator
M = NextModule->Imports.begin(),
MEnd = NextModule->Imports.end();
M != MEnd; ++M) {
if (!Skipped[(*M)->Index]) {
Stack.push_back(*M);
Skipped[(*M)->Index] = true;
}
// Visit the module.
Visited[CurrentModule->Index] = true;
if (!Visitor(*CurrentModule, UserData))
continue;
// The visitor has requested that cut off visitation of any
// 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).
for (llvm::SetVector<ModuleFile *>::iterator
M = NextModule->Imports.begin(),
MEnd = NextModule->Imports.end();
M != MEnd; ++M) {
if (!Visited[(*M)->Index]) {
Stack.push_back(*M);
Visited[(*M)->Index] = true;
}
}
continue;
}
// For any module that this module depends on, push it on the
// stack (if it hasn't already been marked as visited).
for (llvm::SetVector<ModuleFile *>::iterator
M = CurrentModule->Imports.begin(),
MEnd = CurrentModule->Imports.end();
M != MEnd; ++M) {
if (Skipped[(*M)->Index])
continue;
// Remove our current module as an impediment to visiting the
// module we depend on. If we were the last unvisited module
// that depends on this particular module, push it into the
// queue to be visited.
unsigned &NumUnusedEdges = UnusedIncomingEdges[(*M)->Index];
if (NumUnusedEdges && (--NumUnusedEdges == 0))
Queue.push_back(*M);
}
if (Stack.empty())
break;
// Pop the next module off the stack.
NextModule = Stack.back();
Stack.pop_back();
} while (true);
}
}