llvm-project/lld/ELF
Rui Ueyama c1835319c9 Parallelize ICF to make LLD's ICF really fast.
ICF is short for Identical Code Folding. It is a size optimization to
identify two or more functions that happened to have the same contents
to merges them. It usually reduces output size by a few percent.

ICF is slow because it is computationally intensive process. I tried
to paralellize it before but failed because I couldn't make a
parallelized version produce consistent outputs. Although it didn't
create broken executables, every invocation of the linker generated
slightly different output, and I couldn't figure out why.

I think I now understand what was going on, and also came up with a
simple algorithm to fix it. So is this patch.

The result is very exciting. Chromium for example has 780,662 input
sections in which 20,774 are reducible by ICF. LLD previously took
7.980 seconds for ICF. Now it finishes in 1.065 seconds.

As a result, LLD can now link a Chromium binary (output size 1.59 GB)
in 10.28 seconds on my machine with ICF enabled. Compared to gold
which takes 40.94 seconds to do the same thing, this is an amazing
number.

From here, I'll describe what we are doing for ICF, what was the
previous problem, and what I did in this patch.

In ICF, two sections are considered identical if they have the same
section flags, section data, and relocations. Relocations are tricky,
becuase two relocations are considered the same if they have the same
relocation type, values, and if they point to the same section _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 is not an easy problem to solve.

What we are doing in LLD is some sort of coloring algorithm. We color
non-identical sections using different colors repeatedly, and sections
in the same color when the algorithm terminates are considered
identical. Here is 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 having color C to see
  if their relocations are the same. Relocations are considered equal
  if their targets have the same color. We then recolor sections that
  have different relocation targets in new 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.

Step 2 is a heavy operation. For Chromium, the first iteration of step
2 takes 2.882 seconds, and the second iteration takes 1.038 seconds,
and in total it needs 23 iterations.

Parallelizing step 1 is easy because we can color each section
independently. This patch does that.

Parallelizing step 2 is tricky. We could work on each color
independently, but we cannot recolor sections in place, because it
will break the invariance that two possibly-identical sections must
have the same color at any moment.

Consider sections S1, S2, S3, S4 in the same color C, where S1 and S2
are identical, S3 and S4 are identical, but S2 and S3 are not. Thread
A is about to recolor S1 and S2 in C'. After thread A recolor S1 in
C', but before recolor S2 in C', other thread B might observe S1 and
S2. Then thread B will conclude that S1 and S2 are different, and it
will split thread B's sections into smaller groups wrongly. Over-
splitting doesn't produce broken results, but it loses a chance to
merge some identical sections. That was the cause of indeterminism.

To fix the problem, I made sections have two colors, namely current
color and next color. At the beginning of each iteration, both colors
are the same. Each thread reads from current color and writes to next
color. In this way, we can avoid threads from reading partial
results. After each iteration, we flip current and next.

This is a very simple solution and is implemented in less than 50
lines of code.

I tested this patch with Chromium and confirmed that this parallelized
ICF produces the identical output as the non-parallelized one.

Differential Revision: https://reviews.llvm.org/D27247

llvm-svn: 288373
2016-12-01 17:09:04 +00:00
..
CMakeLists.txt Remove a file that is too short to be an independent file. 2016-11-19 23:26:41 +00:00
Config.h [ELF] - Implemented -N (-omagic) command line option. 2016-11-29 09:43:51 +00:00
Driver.cpp [ELF][MIPS] Restore Config->Threads for MIPS targets 2016-11-29 10:24:00 +00:00
Driver.h Remove a file that is too short to be an independent file. 2016-11-19 23:26:41 +00:00
DriverUtils.cpp [ELF] Better error reporting for linker scripts 2016-11-21 15:49:56 +00:00
EhFrame.cpp Move getLocation from Relocations.cpp to InputSection.cpp. 2016-11-25 18:51:53 +00:00
EhFrame.h [ELF] Print error location in .eh_frame parser 2016-11-23 09:45:17 +00:00
Error.cpp Make getColorDiagnostics return a boolean value instead of an enum. 2016-11-26 15:10:01 +00:00
Error.h Update comment. 2016-11-24 01:44:21 +00:00
GdbIndex.cpp Define toString() as a generic function to get a string for error message. 2016-11-23 18:07:33 +00:00
GdbIndex.h [ELF] - Partial support of --gdb-index command line option (Part 1). 2016-10-20 09:19:48 +00:00
ICF.cpp Parallelize ICF to make LLD's ICF really fast. 2016-12-01 17:09:04 +00:00
ICF.h Do not pass Symtab to markLive/doICF since Symtab is globally accessible. 2016-05-02 19:30:42 +00:00
InputFiles.cpp Use StringRefZ explicitly instead of const char *. 2016-11-29 19:11:39 +00:00
InputFiles.h Move typedefs inside a class definition. 2016-11-25 18:51:56 +00:00
InputSection.cpp [ELF] - Disable emiting multiple output sections when merging is disabled. 2016-11-29 16:11:09 +00:00
InputSection.h Parallelize ICF to make LLD's ICF really fast. 2016-12-01 17:09:04 +00:00
LTO.cpp Introduce StringRefZ class to represent null-terminated strings. 2016-11-29 18:05:04 +00:00
LTO.h [ELF] Be compliant with LLVM and rename Lto into LTO. NFCI. 2016-11-26 05:37:04 +00:00
LinkerScript.cpp Make get{Line,Column}Number members of StringParser. 2016-12-01 04:36:49 +00:00
LinkerScript.h [ELF] Print file:line for 'undefined section' errors 2016-11-28 09:58:04 +00:00
MarkLive.cpp Parse relocations only once. 2016-11-10 14:53:24 +00:00
Memory.cpp Replace GAlloc with a template function. 2016-11-01 21:06:40 +00:00
Memory.h [ELF] - Fix mistype. NFC. 2016-11-08 15:26:21 +00:00
Mips.cpp [ELF][MIPS] N32 ABI support 2016-11-05 22:58:01 +00:00
Options.td [ELF] - Implemented -N (-omagic) command line option. 2016-11-29 09:43:51 +00:00
OutputSections.cpp [ELF] Refactor target error messages 2016-11-29 08:05:44 +00:00
OutputSections.h [ELF] Refactor target error messages 2016-11-29 08:05:44 +00:00
README.md Update the documents of the new LLD. 2016-03-12 06:06:40 +00:00
Relocations.cpp Add `isRelExprOneOf` helper 2016-12-01 05:43:48 +00:00
Relocations.h Add `isRelExprOneOf` helper 2016-12-01 05:43:48 +00:00
ScriptParser.cpp Simplify ScriptParser. 2016-12-01 04:36:54 +00:00
ScriptParser.h Simplify ScriptParser. 2016-12-01 04:36:54 +00:00
Strings.cpp Introduce StringRefZ class to represent null-terminated strings. 2016-11-29 18:05:04 +00:00
Strings.h Introduce StringRefZ class to represent null-terminated strings. 2016-11-29 18:05:04 +00:00
SymbolTable.cpp Introduce StringRefZ class to represent null-terminated strings. 2016-11-29 18:05:04 +00:00
SymbolTable.h Introduce StringRefZ class to represent null-terminated strings. 2016-11-29 18:05:04 +00:00
Symbols.cpp Introduce StringRefZ class to represent null-terminated strings. 2016-11-29 18:05:04 +00:00
Symbols.h Introduce StringRefZ class to represent null-terminated strings. 2016-11-29 18:05:04 +00:00
SyntheticSections.cpp [ELF] - Add support of proccessing of the rest allocatable synthetic sections from linkerscript. 2016-11-29 16:05:27 +00:00
SyntheticSections.h [ELF] - Add support of proccessing of the rest allocatable synthetic sections from linkerscript. 2016-11-29 16:05:27 +00:00
Target.cpp [ELF] Add support for static TLS to ARM 2016-11-29 16:23:50 +00:00
Target.h [ELF] Refactor getDynRel to print error location 2016-11-25 08:56:36 +00:00
Thunks.cpp Split Header into individual fields. 2016-11-09 01:42:41 +00:00
Thunks.h Attempt to fix buildbots. 2016-07-09 23:02:37 +00:00
Writer.cpp [ELF] - Add support of proccessing of the rest allocatable synthetic sections from linkerscript. 2016-11-29 16:05:27 +00:00
Writer.h [ELF] Refactor target error messages 2016-11-29 08:05:44 +00:00

README.md

See docs/NewLLD.rst