[cfe-commits] r173692 - Eliminate memory allocation from most invocations of

Douglas Gregor dgregor at apple.com
Mon Jan 28 08:46:33 PST 2013


Author: dgregor
Date: Mon Jan 28 10:46:33 2013
New Revision: 173692

URL: http://llvm.org/viewvc/llvm-project?rev=173692&view=rev
Log:
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.

Modified:
    cfe/trunk/include/clang/Serialization/ModuleManager.h
    cfe/trunk/lib/Serialization/ModuleManager.cpp

Modified: cfe/trunk/include/clang/Serialization/ModuleManager.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ModuleManager.h?rev=173692&r1=173691&r2=173692&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ModuleManager.h (original)
+++ cfe/trunk/include/clang/Serialization/ModuleManager.h Mon Jan 28 10:46:33 2013
@@ -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;

Modified: cfe/trunk/lib/Serialization/ModuleManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ModuleManager.cpp?rev=173692&r1=173691&r2=173692&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ModuleManager.cpp (original)
+++ cfe/trunk/lib/Serialization/ModuleManager.cpp Mon Jan 28 10:46:33 2013
@@ -162,17 +162,37 @@ void ModuleManager::updateModulesInCommo
   }
 }
 
+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)(Mod
     // 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)(Mod
     {
       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)(Mod
     // 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)(Mod
              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.





More information about the cfe-commits mailing list