<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Sun, Oct 22, 2017 at 12:25 PM, Sean Silva <span dir="ltr"><<a href="mailto:chisophugis@gmail.com" target="_blank">chisophugis@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto">Do you know how much of the savings is from reducing the size of Section piece vs the OffsetMap? IIRC the offset map was just an optimization, so if that is turning out to be a major memory hog then maybe we want to reconsider the approach.</div></blockquote><div><br></div><div>This patch didn't make SectionPiece smaller. It is still 16 bytes as before.</div><div><br></div><div>But you made a very good point. By removing OffsetMap, we can cut another 566 MiB of memory, and that change actually made lld slightly faster. That's a surprising result because last time I measured, OffsetMap was beneficial. I don't know what has changed since the last experiment, but looks like there's no reason to keep OffsetMap.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><span class="m_-4027178359719902171HOEnZb"><font color="#888888"><div dir="auto">-- Sean Silva</div></font></span></div><div class="m_-4027178359719902171HOEnZb"><div class="m_-4027178359719902171h5"><div class="gmail_extra"><br><div class="gmail_quote">On Oct 21, 2017 4:20 PM, "Rui Ueyama via llvm-commits" <<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a>> wrote:<br type="attribution"><blockquote class="m_-4027178359719902171m_77295083293871147quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: ruiu<br>
Date: Sat Oct 21 16:20:13 2017<br>
New Revision: 316280<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=316280&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject?rev=316280&view=rev</a><br>
Log:<br>
Assume that mergeable input sections are smaller than 4 GiB.<br>
<br>
By assuming that mergeable input sections are smaller than 4 GiB,<br>
lld's memory usage when linking clang with debug info drops from<br>
2.788 GiB to 2.019 GiB (measured by valgrind, and that does not include<br>
memory space for mmap'ed files). I think that's a reasonable assumption<br>
given such a large RAM savings, so this patch.<br>
<br>
According to valgrind, gold needs 3.54 GiB of RAM to do the same thing.<br>
<br>
NB: This patch does not introduce a limitation on the size of<br>
output sections. You can still create sections larger than 4 GiB.<br>
<br>
Modified:<br>
    lld/trunk/ELF/InputSection.cpp<br>
    lld/trunk/ELF/InputSection.h<br>
    lld/trunk/ELF/SyntheticSection<wbr>s.cpp<br>
<br>
Modified: lld/trunk/ELF/InputSection.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=316280&r1=316279&r2=316280&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/lld/trunk/ELF/InputSecti<wbr>on.cpp?rev=316280&r1=316279&r2<wbr>=316280&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lld/trunk/ELF/InputSection.cpp (original)<br>
+++ lld/trunk/ELF/InputSection.cpp Sat Oct 21 16:20:13 2017<br>
@@ -871,13 +871,15 @@ SyntheticSection *MergeInputSection::get<br>
 void MergeInputSection::splitString<wbr>s(ArrayRef<uint8_t> Data, size_t EntSize) {<br>
   size_t Off = 0;<br>
   bool IsAlloc = this->Flags & SHF_ALLOC;<br>
+<br>
   while (!Data.empty()) {<br>
     size_t End = findNull(Data, EntSize);<br>
     if (End == StringRef::npos)<br>
       fatal(toString(this) + ": string is not null terminated");<br>
     size_t Size = End + EntSize;<br>
-    Pieces.emplace_back(Off, !IsAlloc);<br>
-    Hashes.push_back(xxHash64(toSt<wbr>ringRef(Data.slice(0, Size))));<br>
+<br>
+    Pieces.emplace_back(Off, xxHash64(toStringRef(Data.slic<wbr>e(0, Size))),<br>
+                        !IsAlloc);<br>
     Data = Data.slice(Size);<br>
     Off += Size;<br>
   }<br>
@@ -890,17 +892,23 @@ void MergeInputSection::splitNonStr<wbr>ings(<br>
   size_t Size = Data.size();<br>
   assert((Size % EntSize) == 0);<br>
   bool IsAlloc = this->Flags & SHF_ALLOC;<br>
-  for (unsigned I = 0, N = Size; I != N; I += EntSize) {<br>
-    Hashes.push_back(xxHash64(toSt<wbr>ringRef(Data.slice(I, EntSize))));<br>
-    Pieces.emplace_back(I, !IsAlloc);<br>
-  }<br>
+<br>
+  for (size_t I = 0; I != Size; I += EntSize)<br>
+    Pieces.emplace_back(I, xxHash64(toStringRef(Data.slic<wbr>e(I, EntSize))),<br>
+                        !IsAlloc);<br>
 }<br>
<br>
 template <class ELFT><br>
 MergeInputSection::MergeInput<wbr>Section(ObjFile<ELFT> *F,<br>
                                      const typename ELFT::Shdr *Header,<br>
                                      StringRef Name)<br>
-    : InputSectionBase(F, Header, Name, InputSectionBase::Merge) {}<br>
+    : InputSectionBase(F, Header, Name, InputSectionBase::Merge) {<br>
+  // In order to reduce memory allocation, we assume that mergeable<br>
+  // sections are smaller than 4 GiB, which is not an unreasonable<br>
+  // assumption as of 2017.<br>
+  if (Data.size() > UINT32_MAX)<br>
+    error(toString(this) + ": section too large");<br>
+}<br>
<br>
 // This function is called after we obtain a complete list of input sections<br>
 // that need to be linked. This is responsible to split section contents<br>
@@ -942,8 +950,7 @@ static It fastUpperBound(It First, It La<br>
 }<br>
<br>
 const SectionPiece *MergeInputSection::getSection<wbr>Piece(uint64_t Offset) const {<br>
-  uint64_t Size = this->Data.size();<br>
-  if (Offset >= Size)<br>
+  if (Data.size() <= Offset)<br>
     fatal(toString(this) + ": entry is past the end of the section");<br>
<br>
   // Find the element this offset points to.<br>
@@ -958,20 +965,20 @@ const SectionPiece *MergeInputSection::g<br>
 // Because contents of a mergeable section is not contiguous in output,<br>
 // it is not just an addition to a base output offset.<br>
 uint64_t MergeInputSection::getOffset(u<wbr>int64_t Offset) const {<br>
+  if (!this->Live)<br>
+    return 0;<br>
+<br>
   // Initialize OffsetMap lazily.<br>
   llvm::call_once(InitOffsetMap<wbr>, [&] {<br>
     OffsetMap.reserve(Pieces.size<wbr>());<br>
-    for (const SectionPiece &Piece : Pieces)<br>
-      OffsetMap[Piece.InputOff] = Piece.OutputOff;<br>
+    for (size_t I = 0; I < Pieces.size(); ++I)<br>
+      OffsetMap[Pieces[I].InputOff] = I;<br>
   });<br>
<br>
   // Find a string starting at a given offset.<br>
   auto It = OffsetMap.find(Offset);<br>
   if (It != OffsetMap.end())<br>
-    return It->second;<br>
-<br>
-  if (!this->Live)<br>
-    return 0;<br>
+    return Pieces[It->second].OutputOff;<br>
<br>
   // If Offset is not at beginning of a section piece, it is not in the map.<br>
   // In that case we need to search from the original section piece vector.<br>
<br>
Modified: lld/trunk/ELF/InputSection.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=316280&r1=316279&r2=316280&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/lld/trunk/ELF/InputSecti<wbr>on.h?rev=316280&r1=316279&r2=3<wbr>16280&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lld/trunk/ELF/InputSection.h (original)<br>
+++ lld/trunk/ELF/InputSection.h Sat Oct 21 16:20:13 2017<br>
@@ -214,15 +214,17 @@ private:<br>
 // have to be as compact as possible, which is why we don't store the size (can<br>
 // be found by looking at the next one) and put the hash in a side table.<br>
 struct SectionPiece {<br>
-  SectionPiece(size_t Off, bool Live)<br>
-      : InputOff(Off), Live(Live || !Config->GcSections), OutputOff(-1) {}<br>
-<br>
-  size_t InputOff : 8 * sizeof(ssize_t) - 1;<br>
-  size_t Live : 1;<br>
-  ssize_t OutputOff;<br>
+  SectionPiece(size_t Off, uint32_t Hash, bool Live)<br>
+      : InputOff(Off), Hash(Hash), OutputOff(-1),<br>
+        Live(Live || !Config->GcSections) {}<br>
+<br>
+  uint32_t InputOff;<br>
+  uint32_t Hash;<br>
+  uint64_t OutputOff : 63;<br>
+  uint64_t Live : 1;<br>
 };<br>
-static_assert(sizeof(SectionP<wbr>iece) == 2 * sizeof(size_t),<br>
-              "SectionPiece is too big");<br>
+<br>
+static_assert(sizeof(SectionP<wbr>iece) == 16, "SectionPiece is too big");<br>
<br>
 // This corresponds to a SHF_MERGE section of an input file.<br>
 class MergeInputSection : public InputSectionBase {<br>
@@ -252,14 +254,9 @@ public:<br>
   LLVM_ATTRIBUTE_ALWAYS_INLINE<br>
   llvm::CachedHashStringRef getData(size_t I) const {<br>
     size_t Begin = Pieces[I].InputOff;<br>
-    size_t End;<br>
-    if (Pieces.size() - 1 == I)<br>
-      End = this->Data.size();<br>
-    else<br>
-      End = Pieces[I + 1].InputOff;<br>
-<br>
-    StringRef S = {(const char *)(this->Data.data() + Begin), End - Begin};<br>
-    return {S, Hashes[I]};<br>
+    size_t End =<br>
+        (Pieces.size() - 1 == I) ? Data.size() : Pieces[I + 1].InputOff;<br>
+    return {toStringRef(Data.slice(Begin, End - Begin)), Pieces[I].Hash};<br>
   }<br>
<br>
   // Returns the SectionPiece at a given input section offset.<br>
@@ -272,9 +269,7 @@ private:<br>
   void splitStrings(ArrayRef<uint8_t> A, size_t Size);<br>
   void splitNonStrings(ArrayRef<uint8<wbr>_t> A, size_t Size);<br>
<br>
-  std::vector<uint32_t> Hashes;<br>
-<br>
-  mutable llvm::DenseMap<uint64_t, uint64_t> OffsetMap;<br>
+  mutable llvm::DenseMap<uint32_t, uint32_t> OffsetMap;<br>
   mutable llvm::once_flag InitOffsetMap;<br>
<br>
   llvm::DenseSet<uint64_t> LiveOffsets;<br>
<br>
Modified: lld/trunk/ELF/SyntheticSection<wbr>s.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=316280&r1=316279&r2=316280&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-pr<wbr>oject/lld/trunk/ELF/SyntheticS<wbr>ections.cpp?rev=316280&r1=3162<wbr>79&r2=316280&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- lld/trunk/ELF/SyntheticSection<wbr>s.cpp (original)<br>
+++ lld/trunk/ELF/SyntheticSection<wbr>s.cpp Sat Oct 21 16:20:13 2017<br>
@@ -2269,10 +2269,9 @@ void MergeNoTailSection::finalizeCo<wbr>ntent<br>
       for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) {<br>
         if (!Sec->Pieces[I].Live)<br>
           continue;<br>
-        CachedHashStringRef Str = Sec->getData(I);<br>
-        size_t ShardId = getShardId(Str.hash());<br>
+        size_t ShardId = getShardId(Sec->Pieces[I].Hash<wbr>);<br>
         if ((ShardId & (Concurrency - 1)) == ThreadId)<br>
-          Sec->Pieces[I].OutputOff = Shards[ShardId].add(Str);<br>
+          Sec->Pieces[I].OutputOff = Shards[ShardId].add(Sec->getDa<wbr>ta(I));<br>
       }<br>
     }<br>
   });<br>
@@ -2294,7 +2293,7 @@ void MergeNoTailSection::finalizeCo<wbr>ntent<br>
     for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I)<br>
       if (Sec->Pieces[I].Live)<br>
         Sec->Pieces[I].OutputOff +=<br>
-            ShardOffsets[getShardId(Sec->g<wbr>etData(I).hash())];<br>
+            ShardOffsets[getShardId(Sec->P<wbr>ieces[I].Hash)];<br>
   });<br>
 }<br>
<br>
<br>
<br>
______________________________<wbr>_________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@lists.llvm.org" target="_blank">llvm-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div>
</div></div></blockquote></div><br></div></div>