Commit e7cb3744 authored by Russell Gallop's avatar Russell Gallop
Browse files

[LLD][ELF] Add time-trace to ELF LLD

This adds some of LLD specific scopes and picks up optimisation scopes
via LTO/ThinLTO. Makes use of TimeProfiler multi-thread support added in
77e6bb3c.

Differential Revision: https://reviews.llvm.org/D71060
parent abe01e17
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -192,6 +192,7 @@ struct Configuration {
  bool trace;
  bool thinLTOEmitImportsFiles;
  bool thinLTOIndexOnly;
  bool timeTraceEnabled;
  bool tocOptimize;
  bool undefinedVersion;
  bool useAndroidRelrTags = false;
@@ -243,6 +244,7 @@ struct Configuration {
  unsigned ltoo;
  unsigned optimize;
  unsigned thinLTOJobs;
  unsigned timeTraceGranularity;
  int32_t splitStackAdjustSize;

  // The following config options do not directly correspond to any
+62 −30
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/TarWriter.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include <cstdlib>
#include <utility>
@@ -487,6 +488,13 @@ void LinkerDriver::main(ArrayRef<const char *> argsArr) {
  if (args.hasArg(OPT_version))
    return;

  // Initialize time trace profiler.
  if (config->timeTraceEnabled)
    timeTraceProfilerInitialize(config->timeTraceGranularity, config->progName);

  {
    llvm::TimeTraceScope timeScope("ExecuteLinker");

    initLLVM();
    createFiles(args);
    if (errorCount())
@@ -506,21 +514,37 @@ void LinkerDriver::main(ArrayRef<const char *> argsArr) {
    switch (config->ekind) {
    case ELF32LEKind:
      link<ELF32LE>(args);
    return;
      break;
    case ELF32BEKind:
      link<ELF32BE>(args);
    return;
      break;
    case ELF64LEKind:
      link<ELF64LE>(args);
    return;
      break;
    case ELF64BEKind:
      link<ELF64BE>(args);
    return;
      break;
    default:
      llvm_unreachable("unknown Config->EKind");
    }
  }

  if (config->timeTraceEnabled) {
    // Write the result of the time trace profiler.
    std::string path = args.getLastArgValue(OPT_time_trace_file_eq).str();
    if (path.empty())
      path = (config->outputFile + ".time-trace").str();
    std::error_code ec;
    raw_fd_ostream os(path, ec, sys::fs::OF_Text);
    if (ec) {
      error("cannot open " + path + ": " + ec.message());
      return;
    }
    timeTraceProfilerWrite(os);
    timeTraceProfilerCleanup();
  }
}

static std::string getRpath(opt::InputArgList &args) {
  std::vector<StringRef> v = args::getStrings(args, OPT_rpath);
  return llvm::join(v.begin(), v.end(), ":");
@@ -958,6 +982,9 @@ static void readConfigs(opt::InputArgList &args) {
      getOldNewOptions(args, OPT_thinlto_object_suffix_replace_eq);
  config->thinLTOPrefixReplace =
      getOldNewOptions(args, OPT_thinlto_prefix_replace_eq);
  config->timeTraceEnabled = args.hasArg(OPT_time_trace);
  config->timeTraceGranularity =
      args::getInteger(args, OPT_time_trace_granularity, 500);
  config->trace = args.hasArg(OPT_trace);
  config->undefined = args::getStrings(args, OPT_undefined);
  config->undefinedVersion =
@@ -1604,6 +1631,7 @@ static Symbol *addUndefined(StringRef name) {
// Because all bitcode files that the program consists of are passed to
// the compiler at once, it can do a whole-program optimization.
template <class ELFT> void LinkerDriver::compileBitcodeFiles() {
  llvm::TimeTraceScope timeScope("LTO");
  // Compile bitcode files and replace bitcode symbols.
  lto.reset(new BitcodeCompiler);
  for (BitcodeFile *file : bitcodeFiles)
@@ -1733,6 +1761,7 @@ template <class ELFT> static uint32_t getAndFeatures() {
// Do actual linking. Note that when this function is called,
// all linker scripts have already been parsed.
template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
  llvm::TimeTraceScope timeScope("Link", StringRef("LinkerDriver::Link"));
  // If a -hash-style option was not given, set to a default value,
  // which varies depending on the target.
  if (!args.hasArg(OPT_hash_style)) {
@@ -1772,8 +1801,11 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) {
  // symbols that we need to the symbol table. This process might
  // add files to the link, via autolinking, these files are always
  // appended to the Files vector.
  {
    llvm::TimeTraceScope timeScope("Parse input files");
    for (size_t i = 0; i < files.size(); ++i)
      parseFile(files[i]);
  }

  // Now that we have every file, we can decide if we will need a
  // dynamic symbol table.
+5 −1
Original line number Diff line number Diff line
@@ -84,6 +84,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/xxhash.h"
#include <algorithm>
#include <atomic>
@@ -525,7 +526,10 @@ template <class ELFT> void ICF<ELFT>::run() {
}

// ICF entry point function.
template <class ELFT> void doIcf() { ICF<ELFT>().run(); }
template <class ELFT> void doIcf() {
  llvm::TimeTraceScope timeScope("ICF");
  ICF<ELFT>().run();
}

template void doIcf<ELF32LE>();
template void doIcf<ELF32BE>();
+3 −0
Original line number Diff line number Diff line
@@ -113,6 +113,9 @@ static lto::Config createConfig() {

  c.HasWholeProgramVisibility = config->ltoWholeProgramVisibility;

  c.TimeTraceEnabled = config->timeTraceEnabled;
  c.TimeTraceGranularity = config->timeTraceGranularity;

  c.CSIRProfile = std::string(config->ltoCSProfileFile);
  c.RunCSIRInstr = config->ltoCSProfileGenerate;

+2 −0
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include "lld/Common/Strings.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Object/ELF.h"
#include "llvm/Support/TimeProfiler.h"
#include <functional>
#include <vector>

@@ -323,6 +324,7 @@ template <class ELFT> void MarkLive<ELFT>::moveToMain() {
// input sections. This function make some or all of them on
// so that they are emitted to the output file.
template <class ELFT> void markLive() {
  llvm::TimeTraceScope timeScope("markLive");
  // If -gc-sections is not given, no sections are removed.
  if (!config->gcSections) {
    for (InputSectionBase *sec : inputSections)
Loading