diff options
Diffstat (limited to 'src/cmd/link/internal/ld/main.go')
-rw-r--r-- | src/cmd/link/internal/ld/main.go | 148 |
1 files changed, 133 insertions, 15 deletions
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 9f9395b757..3772c5090c 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -34,10 +34,12 @@ import ( "bufio" "cmd/internal/objabi" "cmd/internal/sys" + "cmd/link/internal/benchmark" "cmd/link/internal/sym" "flag" "log" "os" + "os/exec" "runtime" "runtime/pprof" "strings" @@ -87,8 +89,6 @@ var ( flagInterpreter = flag.String("I", "", "use `linker` as ELF dynamic linker") FlagDebugTramp = flag.Int("debugtramp", 0, "debug trampolines") FlagStrictDups = flag.Int("strictdups", 0, "sanity check duplicate symbol contents during object file reading (1=warn 2=err).") - flagNewobj = flag.Bool("newobj", false, "use new object file format") - FlagRound = flag.Int("R", -1, "set address rounding `quantum`") FlagTextAddr = flag.Int64("T", -1, "set text segment `address`") flagEntrySymbol = flag.String("E", "", "set `entry` symbol name") @@ -96,6 +96,11 @@ var ( cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") memprofile = flag.String("memprofile", "", "write memory profile to `file`") memprofilerate = flag.Int64("memprofilerate", 0, "set runtime.MemProfileRate to `rate`") + + benchmarkFlag = flag.String("benchmark", "", "set to 'mem' or 'cpu' to enable phase benchmarking") + benchmarkFileFlag = flag.String("benchmarkprofile", "", "emit phase profiles to `base`_phase.{cpu,mem}prof") + + flagGo115Newobj = flag.Bool("go115newobj", true, "use new object file format") ) // Main is the main entry point for the linker code. @@ -135,6 +140,10 @@ func Main(arch *sys.Arch, theArch Arch) { objabi.Flagparse(usage) + if !*flagGo115Newobj { + oldlink() + } + switch *flagHeadType { case "": case "windowsgui": @@ -170,13 +179,29 @@ func Main(arch *sys.Arch, theArch Arch) { interpreter = *flagInterpreter + // enable benchmarking + var bench *benchmark.Metrics + if len(*benchmarkFlag) != 0 { + if *benchmarkFlag == "mem" { + bench = benchmark.New(benchmark.GC, *benchmarkFileFlag) + } else if *benchmarkFlag == "cpu" { + bench = benchmark.New(benchmark.NoGC, *benchmarkFileFlag) + } else { + Errorf(nil, "unknown benchmark flag: %q", *benchmarkFlag) + usage() + } + } + + bench.Start("libinit") libinit(ctxt) // creates outfile if ctxt.HeadType == objabi.Hunknown { ctxt.HeadType.Set(objabi.GOOS) } + bench.Start("computeTLSOffset") ctxt.computeTLSOffset() + bench.Start("Archinit") thearch.Archinit(ctxt) if ctxt.linkShared && !ctxt.IsELF { @@ -207,47 +232,84 @@ func Main(arch *sys.Arch, theArch Arch) { default: addlibpath(ctxt, "command line", "command line", flag.Arg(0), "main", "") } + bench.Start("loadlib") ctxt.loadlib() + bench.Start("deadcode") deadcode(ctxt) - if *flagNewobj { - ctxt.loadlibfull() // XXX do it here for now - } + + bench.Start("linksetup") ctxt.linksetup() - ctxt.dostrdata() - dwarfGenerateDebugInfo(ctxt) + bench.Start("dostrdata") + ctxt.dostrdata() if objabi.Fieldtrack_enabled != 0 { - fieldtrack(ctxt) + bench.Start("fieldtrack") + fieldtrack(ctxt.Arch, ctxt.loader) } - ctxt.mangleTypeSym() + + bench.Start("dwarfGenerateDebugInfo") + dwarfGenerateDebugInfo(ctxt) + + bench.Start("callgraph") ctxt.callgraph() - ctxt.doelf() - if ctxt.HeadType == objabi.Hdarwin { + bench.Start("dostkcheck") + ctxt.dostkcheck() + + bench.Start("mangleTypeSym") + ctxt.mangleTypeSym() + + if ctxt.IsELF { + bench.Start("doelf") + ctxt.doelf() + } + if ctxt.IsDarwin() { + bench.Start("domacho") ctxt.domacho() } - ctxt.dostkcheck() - if ctxt.HeadType == objabi.Hwindows { + if ctxt.IsWindows() { + bench.Start("dope") ctxt.dope() + bench.Start("windynrelocsyms") ctxt.windynrelocsyms() } - if ctxt.HeadType == objabi.Haix { + if ctxt.IsAIX() { + bench.Start("doxcoff") ctxt.doxcoff() } + bench.Start("textbuildid") + ctxt.textbuildid() + bench.Start("addexport") + setupdynexp(ctxt) + ctxt.setArchSyms(BeforeLoadlibFull) ctxt.addexport() + + bench.Start("loadlibfull") + ctxt.loadlibfull() // XXX do it here for now + + bench.Start("Gentext") thearch.Gentext(ctxt) // trampolines, call stubs, etc. - ctxt.textbuildid() + bench.Start("textaddress") ctxt.textaddress() + bench.Start("pclntab") ctxt.pclntab() + bench.Start("findfunctab") ctxt.findfunctab() + bench.Start("typelink") ctxt.typelink() + bench.Start("symtab") ctxt.symtab() + bench.Start("buildinfo") ctxt.buildinfo() + bench.Start("dodata") ctxt.dodata() + bench.Start("address") order := ctxt.address() + bench.Start("dwarfcompress") dwarfcompress(ctxt) + bench.Start("layout") filesize := ctxt.layout(order) // Write out the output file. @@ -266,25 +328,36 @@ func Main(arch *sys.Arch, theArch Arch) { if outputMmapped { // Asmb will redirect symbols to the output file mmap, and relocations // will be applied directly there. + bench.Start("Asmb") thearch.Asmb(ctxt) + bench.Start("reloc") ctxt.reloc() + bench.Start("Munmap") ctxt.Out.Munmap() } else { // If we don't mmap, we need to apply relocations before // writing out. + bench.Start("reloc") ctxt.reloc() + bench.Start("Asmb") thearch.Asmb(ctxt) } + bench.Start("Asmb2") thearch.Asmb2(ctxt) + bench.Start("undef") ctxt.undef() + bench.Start("hostlink") ctxt.hostlink() if ctxt.Debugvlog != 0 { ctxt.Logf("%d symbols\n", len(ctxt.Syms.Allsym)) ctxt.Logf("%d liveness data\n", liveness) } + bench.Start("Flush") ctxt.Bso.Flush() + bench.Start("archive") ctxt.archive() + bench.Report(os.Stdout) errorexit() } @@ -336,3 +409,48 @@ func startProfile() { }) } } + +// Invoke the old linker and exit. +func oldlink() { + linker := os.Args[0] + if strings.HasSuffix(linker, "link") { + linker = linker[:len(linker)-4] + "oldlink" + } else if strings.HasSuffix(linker, "link.exe") { + linker = linker[:len(linker)-8] + "oldlink.exe" + } else { + log.Fatal("cannot find oldlink. arg0=", linker) + } + + // Copy args, filter out -go115newobj flag + args := make([]string, 0, len(os.Args)-1) + skipNext := false + for i, a := range os.Args { + if i == 0 { + continue // skip arg0 + } + if skipNext { + skipNext = false + continue + } + if a == "-go115newobj" { + skipNext = true + continue + } + if strings.HasPrefix(a, "-go115newobj=") { + continue + } + args = append(args, a) + } + + cmd := exec.Command(linker, args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() + if err == nil { + os.Exit(0) + } + if _, ok := err.(*exec.ExitError); ok { + os.Exit(2) // would be nice to use ExitError.ExitCode(), but that is too new + } + log.Fatal("invoke oldlink failed:", err) +} |