[lld] r288409 - Updates file comments and variable names.

Rui Ueyama via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 1 11:45:23 PST 2016


Author: ruiu
Date: Thu Dec  1 13:45:22 2016
New Revision: 288409

URL: http://llvm.org/viewvc/llvm-project?rev=288409&view=rev
Log:
Updates file comments and variable names.

Use "color" instead of "group id" to describe the ICF algorithm.

Modified:
    lld/trunk/ELF/ICF.cpp
    lld/trunk/ELF/InputSection.h

Modified: lld/trunk/ELF/ICF.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/ICF.cpp?rev=288409&r1=288408&r2=288409&view=diff
==============================================================================
--- lld/trunk/ELF/ICF.cpp (original)
+++ lld/trunk/ELF/ICF.cpp Thu Dec  1 13:45:22 2016
@@ -7,51 +7,62 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// Identical Code Folding is a feature to merge sections not by name (which
-// is regular comdat handling) but by contents. If two non-writable sections
-// have the same data, relocations, attributes, etc., then the two
-// are considered identical and merged by the linker. This optimization
-// makes outputs smaller.
-//
-// ICF is theoretically a problem of reducing graphs by merging as many
-// identical subgraphs as possible if we consider sections as vertices and
-// relocations as edges. It may sound simple, but it is a bit more
-// complicated than you might think. The order of processing sections
-// matters because merging two sections can make other sections, whose
-// relocations now point to the same section, mergeable. Graphs may contain
-// cycles. We need a sophisticated algorithm to do this properly and
-// efficiently.
-//
-// What we do in this file is this. We split sections into groups. Sections
-// in the same group are considered identical.
-//
-// We begin by optimistically putting all sections into a single equivalence
-// class. Then we apply a series of checks that split this initial
-// equivalence class into more and more refined equivalence classes based on
-// the properties by which a section can be distinguished.
-//
-// We begin by checking that the section contents and flags are the
-// same. This only needs to be done once since these properties don't depend
-// on the current equivalence class assignment.
-//
-// Then we split the equivalence classes based on checking that their
-// relocations are the same, where relocation targets are compared by their
-// equivalence class, not the concrete section. This may need to be done
-// multiple times because as the equivalence classes are refined, two
-// sections that had a relocation target in the same equivalence class may
-// now target different equivalence classes, and hence these two sections
-// must be put in different equivalence classes (whereas in the previous
-// iteration they were not since the relocation target was the same.)
-//
-// Our algorithm is smart enough to merge the following mutually-recursive
-// functions.
+// ICF is short for Identical Code Folding. That is a size optimization to
+// identify and merge two or more read-only sections (typically functions)
+// that happened to have the same contents. It usually reduces output size
+// by a few percent.
+//
+// In ICF, two sections are considered identical if they have the same
+// section flags, section data, and relocations. Relocations are tricky,
+// because two relocations are considered the same if they have the same
+// relocation types, values, and if they point to the same sections *in
+// terms of ICF*.
+//
+// Here is an example. If foo and bar defined below are compiled to the
+// same machine instructions, ICF can and should merge the two, although
+// their relocations point to each other.
 //
 //   void foo() { bar(); }
 //   void bar() { foo(); }
 //
-// This algorithm is so-called "optimistic" algorithm described in
-// http://research.google.com/pubs/pub36912.html. (Note that what GNU
-// gold implemented is different from the optimistic algorithm.)
+// If you merge the two, their relocations point to the same section and
+// thus you know they are mergeable, but how do we know they are mergeable
+// in the first place? This is not an easy problem to solve.
+//
+// What we are doing in LLD is some sort of coloring algorithm.
+//
+// We color non-identical sections in different colors repeatedly.
+// Sections in the same color when the algorithm terminates are considered
+// identical. Here are the details:
+//
+// 1. First, we color all sections using their hash values of section
+//    types, section contents, and numbers of relocations. At this moment,
+//    relocation targets are not taken into account. We just color
+//    sections that apparently differ in different colors.
+//
+// 2. Next, for each color C, we visit sections in color C to compare
+//    relocation target colors.  We recolor sections A and B in different
+//    colors if A's and B's relocations are different in terms of target
+//    colors.
+//
+// 3. If we recolor some section in step 2, relocations that were
+//    previously pointing to the same color targets may now be pointing to
+//    different colors. Therefore, repeat 2 until a convergence is
+//    obtained.
+//
+// 4. For each color C, pick an arbitrary section in color C, and merges
+//    other sections in color C with it.
+//
+// For small programs, this algorithm needs 3-5 iterations. For large
+// programs such as Chromium, it takes more than 20 iterations.
+//
+// We parallelize each step so that multiple threads can work on different
+// colors concurrently. That gave us a large performance boost when
+// applying ICF on large programs. For example, MSVC link.exe or GNU gold
+// takes 10-20 seconds to apply ICF on Chromium, whose output size is
+// about 1.5 GB, but LLD can finish it in less than 2 seconds on a 2.8 GHz
+// 40 core machine. Even without threading, LLD's ICF is still faster than
+// MSVC or gold though.
 //
 //===----------------------------------------------------------------------===//
 
@@ -119,8 +130,7 @@ template <class ELFT> static bool isElig
          S->Name != ".init" && S->Name != ".fini";
 }
 
-// Before calling this function, all sections in range R must have the
-// same group ID.
+// Split R into smaller ranges by recoloring its members.
 template <class ELFT> void ICF<ELFT>::segregate(Range *R, bool Constant) {
   // This loop rearranges sections in range R so that all sections
   // that are equal in terms of equals{Constant,Variable} are contiguous
@@ -158,24 +168,23 @@ template <class ELFT> void ICF<ELFT>::se
     }
     R->End = Mid;
 
-    // Update GroupIds for the new group members.
+    // Update the new group member colors.
     //
-    // Note on GroupId[0] and GroupId[1]: we have two storages for
-    // group IDs. At the beginning of each iteration of the main loop,
-    // both have the same ID. GroupId[0] contains the current ID, and
-    // GroupId[1] contains the next ID which will be used in the next
-    // iteration.
+    // Note on Color[0] and Color[1]: we have two storages for colors.
+    // At the beginning of each iteration of the main loop, both have
+    // the same color. Color[0] contains the current color, and Color[1]
+    // contains the next color which will be used in the next iteration.
     //
     // Recall that other threads may be working on other ranges. They
-    // may be reading group IDs that we are about to update. We cannot
-    // update group IDs in place because it breaks the invariance that
-    // all sections in the same group must have the same ID. In other
-    // words, the following for loop is not an atomic operation, and
-    // that is observable from other threads.
+    // may be reading colors that we are about to update. We cannot
+    // update colors in place because it breaks the invariance that
+    // all sections in the same group must have the same color. In
+    // other words, the following for loop is not an atomic operation,
+    // and that is observable from other threads.
     //
-    // By writing new IDs to write-only places, we can keep the invariance.
+    // By writing new colors to write-only places, we can keep the invariance.
     for (size_t I = Mid; I < End; ++I)
-      Sections[I]->GroupId[(Cnt + 1) % 2] = Id;
+      Sections[I]->Color[(Cnt + 1) % 2] = Id;
 
     R = NewRange;
   }
@@ -216,13 +225,13 @@ template <class RelTy>
 bool ICF<ELFT>::variableEq(const InputSection<ELFT> *A, ArrayRef<RelTy> RelsA,
                            const InputSection<ELFT> *B, ArrayRef<RelTy> RelsB) {
   auto Eq = [&](const RelTy &RA, const RelTy &RB) {
+    // The two sections must be identical.
     SymbolBody &SA = A->getFile()->getRelocTargetSym(RA);
     SymbolBody &SB = B->getFile()->getRelocTargetSym(RB);
     if (&SA == &SB)
       return true;
 
-    // Or, the symbols should be pointing to the same section
-    // in terms of the group ID.
+    // Or, the two sections must have the same color.
     auto *DA = dyn_cast<DefinedRegular<ELFT>>(&SA);
     auto *DB = dyn_cast<DefinedRegular<ELFT>>(&SB);
     if (!DA || !DB)
@@ -234,16 +243,16 @@ bool ICF<ELFT>::variableEq(const InputSe
     auto *Y = dyn_cast<InputSection<ELFT>>(DB->Section);
     if (!X || !Y)
       return false;
-    if (X->GroupId[Cnt % 2] == 0)
+    if (X->Color[Cnt % 2] == 0)
       return false;
 
     // Performance hack for single-thread. If no other threads are
-    // running, we can safely read next GroupIDs as there is no race
+    // running, we can safely read next colors as there is no race
     // condition. This optimization may reduce the number of
     // iterations of the main loop because we can see results of the
     // same iteration.
     size_t Idx = (Config->Threads ? Cnt : Cnt + 1) % 2;
-    return X->GroupId[Idx] == Y->GroupId[Idx];
+    return X->Color[Idx] == Y->Color[Idx];
   };
 
   return std::equal(RelsA.begin(), RelsA.end(), RelsB.begin(), Eq);
@@ -274,45 +283,45 @@ template <class ELFT> void ICF<ELFT>::ru
       if (isEligible(S))
         Sections.push_back(S);
 
-  // Initially, we use hash values as section group IDs. Therefore,
-  // if two sections have the same ID, they are likely (but not
+  // Initially, we use hash values to color sections. Therefore, if
+  // two sections have the same color, they are likely (but not
   // guaranteed) to have the same static contents in terms of ICF.
   for (InputSection<ELFT> *S : Sections)
-    // Set MSB to 1 to avoid collisions with non-hash IDs.
-    S->GroupId[0] = S->GroupId[1] = getHash(S) | (1 << 31);
+    // Set MSB to 1 to avoid collisions with non-hash colors.
+    S->Color[0] = S->Color[1] = getHash(S) | (1 << 31);
 
   // From now on, sections in Sections are ordered so that sections in
-  // the same group are consecutive in the vector.
+  // the same color are consecutive in the vector.
   std::stable_sort(Sections.begin(), Sections.end(),
                    [](InputSection<ELFT> *A, InputSection<ELFT> *B) {
-                     if (A->GroupId[0] != B->GroupId[0])
-                       return A->GroupId[0] < B->GroupId[0];
+                     if (A->Color[0] != B->Color[0])
+                       return A->Color[0] < B->Color[0];
                      // Within a group, put the highest alignment
                      // requirement first, so that's the one we'll keep.
                      return B->Alignment < A->Alignment;
                    });
 
-  // Split sections into groups by ID. And then we are going to
-  // split groups into more and more smaller groups.
-  // Note that we do not add single element groups because they
-  // are already the smallest.
+  // Create ranges in which each range contains sections in the same
+  // color. And then we are going to split ranges into more and more
+  // smaller ranges. Note that we do not add single element ranges
+  // because they are already the smallest.
   Ranges.reserve(Sections.size());
   for (size_t I = 0, E = Sections.size(); I < E - 1;) {
     // Let J be the first index whose element has a different ID.
     size_t J = I + 1;
-    while (J < E && Sections[I]->GroupId[0] == Sections[J]->GroupId[0])
+    while (J < E && Sections[I]->Color[0] == Sections[J]->Color[0])
       ++J;
     if (J - I > 1)
       Ranges.push_back({I, J});
     I = J;
   }
 
-  // This function copies new GroupIds from former write-only space to
-  // former read-only space, so that we can flip GroupId[0] and GroupId[1].
-  // Note that new GroupIds are always be added to end of Ranges.
+  // This function copies colors from former write-only space to former
+  // read-only space, so that we can flip Color[0] and Color[1]. Note
+  // that new colors are always be added to end of Ranges.
   auto Copy = [&](Range &R) {
     for (size_t I = R.Begin; I < R.End; ++I)
-      Sections[I]->GroupId[Cnt % 2] = Sections[I]->GroupId[(Cnt + 1) % 2];
+      Sections[I]->Color[Cnt % 2] = Sections[I]->Color[(Cnt + 1) % 2];
   };
 
   // Compare static contents and assign unique IDs for each static content.
@@ -321,7 +330,7 @@ template <class ELFT> void ICF<ELFT>::ru
   foreach(End, Ranges.end(), Copy);
   ++Cnt;
 
-  // Split groups by comparing relocations until convergence is obtained.
+  // Split ranges by comparing relocations until convergence is obtained.
   for (;;) {
     auto End = Ranges.end();
     foreach(Ranges.begin(), End, [&](Range &R) { segregate(&R, false); });
@@ -334,7 +343,7 @@ template <class ELFT> void ICF<ELFT>::ru
 
   log("ICF needed " + Twine(Cnt) + " iterations");
 
-  // Merge sections in the same group.
+  // Merge sections in the same colors.
   for (Range R : Ranges) {
     if (R.End - R.Begin == 1)
       continue;

Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=288409&r1=288408&r2=288409&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Thu Dec  1 13:45:22 2016
@@ -289,7 +289,7 @@ public:
   void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels);
 
   // Used by ICF.
-  uint32_t GroupId[2] = {0, 0};
+  uint32_t Color[2] = {0, 0};
 
   // Called by ICF to merge two input sections.
   void replace(InputSection<ELFT> *Other);




More information about the llvm-commits mailing list