Optimize ModuleManager::visit() by precomputing the visitation order
authorDouglas Gregor <dgregor@apple.com>
Fri, 25 Jan 2013 22:25:23 +0000 (22:25 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 25 Jan 2013 22:25:23 +0000 (22:25 +0000)
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%.

llvm-svn: 173512

clang/include/clang/Serialization/ModuleManager.h
clang/lib/Serialization/ModuleManager.cpp

index 512d7e9..465da76 100644 (file)
@@ -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;
index c600c05..f3fe2b9 100644 (file)
@@ -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);
   }
 }