зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
3d115cfd1b
Коммит
d07865b42d
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче