From f7976edc1ec48ae9f96bcc7524ae02373d126869 Mon Sep 17 00:00:00 2001 From: Wenlei He Date: Thu, 11 Nov 2021 18:28:47 -0800 Subject: [PATCH] [llvm-profgen] Add switch to allow use of first loadable segment for calculating offset Adding `-use-loadable-segment-as-base` to allow use of first loadable segment for calculating offset. By default first executable segment is used for calculating offset. The switch helps compatibility with unsymbolized profile generated from older tools. Differential Revision: https://reviews.llvm.org/D113727 --- .../tools/llvm-profgen/inline-cs-pseudoprobe.test | 21 +++++++++++++ llvm/tools/llvm-profgen/PerfReader.cpp | 34 +++++++++++++++++----- llvm/tools/llvm-profgen/ProfiledBinary.cpp | 6 +++- llvm/tools/llvm-profgen/ProfiledBinary.h | 4 +++ 4 files changed, 57 insertions(+), 8 deletions(-) diff --git a/llvm/test/tools/llvm-profgen/inline-cs-pseudoprobe.test b/llvm/test/tools/llvm-profgen/inline-cs-pseudoprobe.test index f2c52e7..648c06e 100644 --- a/llvm/test/tools/llvm-profgen/inline-cs-pseudoprobe.test +++ b/llvm/test/tools/llvm-profgen/inline-cs-pseudoprobe.test @@ -1,5 +1,9 @@ ; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/inline-cs-pseudoprobe.perfscript --binary=%S/Inputs/inline-cs-pseudoprobe.perfbin --output=%t --skip-symbolization --profile-summary-cold-count=0 --use-offset=0 ; RUN: FileCheck %s --input-file %t --check-prefix=CHECK-UNWINDER +; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/inline-cs-pseudoprobe.perfscript --binary=%S/Inputs/inline-cs-pseudoprobe.perfbin --output=%t --skip-symbolization --profile-summary-cold-count=0 --use-offset=1 +; RUN: FileCheck %s --input-file %t --check-prefix=CHECK-UNWINDER-OFFSET +; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/inline-cs-pseudoprobe.perfscript --binary=%S/Inputs/inline-cs-pseudoprobe.perfbin --output=%t --skip-symbolization --profile-summary-cold-count=0 --use-offset=1 --use-first-loadable-segment-as-base=1 +; RUN: FileCheck %s --input-file %t --check-prefix=CHECK-UNWINDER-OFFSET2 ; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/inline-cs-pseudoprobe.perfscript --binary=%S/Inputs/inline-cs-pseudoprobe.perfbin --output=%t --profile-summary-cold-count=0 ; RUN: FileCheck %s --input-file %t @@ -27,6 +31,23 @@ ; CHECK-UNWINDER-NEXT: 20182b->201800:1 ; CHECK-UNWINDER-NEXT: 201858->20180e:15 + +; CHECK-UNWINDER-OFFSET: 3 +; CHECK-UNWINDER-OFFSET-NEXT: 800-858:1 +; CHECK-UNWINDER-OFFSET-NEXT: 80e-82b:1 +; CHECK-UNWINDER-OFFSET-NEXT: 80e-858:13 +; CHECK-UNWINDER-OFFSET-NEXT: 2 +; CHECK-UNWINDER-OFFSET-NEXT: 82b->800:1 +; CHECK-UNWINDER-OFFSET-NEXT: 858->80e:15 + +; CHECK-UNWINDER-OFFSET2: 3 +; CHECK-UNWINDER-OFFSET2-NEXT: 1800-1858:1 +; CHECK-UNWINDER-OFFSET2-NEXT: 180e-182b:1 +; CHECK-UNWINDER-OFFSET2-NEXT: 180e-1858:13 +; CHECK-UNWINDER-OFFSET2-NEXT: 2 +; CHECK-UNWINDER-OFFSET2-NEXT: 182b->1800:1 +; CHECK-UNWINDER-OFFSET2-NEXT: 1858->180e:15 + ; clang -O3 -fexperimental-new-pass-manager -fuse-ld=lld -fpseudo-probe-for-profiling ; -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -Xclang -mdisable-tail-calls ; -g test.c -o a.out diff --git a/llvm/tools/llvm-profgen/PerfReader.cpp b/llvm/tools/llvm-profgen/PerfReader.cpp index deafa4d..e39fb01 100644 --- a/llvm/tools/llvm-profgen/PerfReader.cpp +++ b/llvm/tools/llvm-profgen/PerfReader.cpp @@ -27,6 +27,13 @@ static cl::opt cl::desc("Work with `--skip-symbolization` or " "`--unsymbolized-profile` to write/read the " "offset instead of virtual address.")); + +static cl::opt UseLoadableSegmentAsBase( + "use-first-loadable-segment-as-base", cl::init(false), cl::ZeroOrMore, + cl::desc("Use first loadable segment address as base address " + "for offsets in unsymbolized profile. By default " + "first executable segment address is used")); + static cl::opt IgnoreStackSamples("ignore-stack-samples", cl::init(false), cl::ZeroOrMore, cl::desc("Ignore call stack samples for hybrid samples " @@ -698,10 +705,19 @@ void PerfScriptReader::writeUnsymbolizedProfile(raw_fd_ostream &OS) { OS.indent(Indent); OS << Counter.size() << "\n"; for (auto &I : Counter) { - uint64_t Start = UseOffset ? I.first.first - : Binary->offsetToVirtualAddr(I.first.first); - uint64_t End = UseOffset ? I.first.second - : Binary->offsetToVirtualAddr(I.first.second); + uint64_t Start = I.first.first; + uint64_t End = I.first.second; + + if (!UseOffset || (UseOffset && UseLoadableSegmentAsBase)) { + Start = Binary->offsetToVirtualAddr(Start); + End = Binary->offsetToVirtualAddr(End); + } + + if (UseOffset && UseLoadableSegmentAsBase) { + Start -= Binary->getFirstLoadableAddress(); + End -= Binary->getFirstLoadableAddress(); + } + OS.indent(Indent); OS << Twine::utohexstr(Start) << Separator << Twine::utohexstr(End) << ":" << I.second << "\n"; @@ -771,9 +787,13 @@ void UnsymbolizedProfileReader::readSampleCounters(TraceStream &TraceIt, Range.second.getAsInteger(16, Target)) exitWithErrorForTraceLine(TraceIt); - if (!UseOffset) { - Source = Binary->virtualAddrToOffset(Source); - Target = Binary->virtualAddrToOffset(Target); + if (!UseOffset || (UseOffset && UseLoadableSegmentAsBase)) { + uint64_t BaseAddr = 0; + if (UseOffset && UseLoadableSegmentAsBase) + BaseAddr = Binary->getFirstLoadableAddress(); + + Source = Binary->virtualAddrToOffset(Source + BaseAddr); + Target = Binary->virtualAddrToOffset(Target + BaseAddr); } Counter[{Source, Target}] += Count; diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.cpp b/llvm/tools/llvm-profgen/ProfiledBinary.cpp index 1cf1d7b..e08a00d 100644 --- a/llvm/tools/llvm-profgen/ProfiledBinary.cpp +++ b/llvm/tools/llvm-profgen/ProfiledBinary.cpp @@ -285,12 +285,16 @@ void ProfiledBinary::setPreferredTextSegmentAddresses(const ELFFile &Obj, // because we may build the tools on non-linux. uint32_t PageSize = 0x1000; for (const typename ELFT::Phdr &Phdr : PhdrRange) { - if ((Phdr.p_type == ELF::PT_LOAD) && (Phdr.p_flags & ELF::PF_X)) { + if (Phdr.p_type == ELF::PT_LOAD) { + if (!FirstLoadableAddress) + FirstLoadableAddress = Phdr.p_vaddr & ~(PageSize - 1U); + if (Phdr.p_flags & ELF::PF_X) { // Segments will always be loaded at a page boundary. PreferredTextSegmentAddresses.push_back(Phdr.p_vaddr & ~(PageSize - 1U)); TextSegmentOffsets.push_back(Phdr.p_offset & ~(PageSize - 1U)); } + } } if (PreferredTextSegmentAddresses.empty()) diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.h b/llvm/tools/llvm-profgen/ProfiledBinary.h index 3c4ed7b..4249b78 100644 --- a/llvm/tools/llvm-profgen/ProfiledBinary.h +++ b/llvm/tools/llvm-profgen/ProfiledBinary.h @@ -173,6 +173,8 @@ class ProfiledBinary { Triple TheTriple; // The runtime base address that the first executable segment is loaded at. uint64_t BaseAddress = 0; + // The runtime base address that the first loadabe segment is loaded at. + uint64_t FirstLoadableAddress = 0; // The preferred load address of each executable segment. std::vector PreferredTextSegmentAddresses; // The file offset of each executable segment. @@ -305,6 +307,8 @@ public: // Return the preferred load address for the first executable segment. uint64_t getPreferredBaseAddress() const { return PreferredTextSegmentAddresses[0]; } + // Return the preferred load address for the first loadable segment. + uint64_t getFirstLoadableAddress() const { return FirstLoadableAddress; } // Return the file offset for the first executable segment. uint64_t getTextSegmentOffset() const { return TextSegmentOffsets[0]; } const std::vector &getPreferredTextSegmentAddresses() const { -- 2.7.4