[llvm] r247874 - GCC AutoFDO profile reader - Initial support.

Dehao Chen via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 16 17:43:34 PDT 2015


Module is only useful for LIPO, so I guess LLVM can just ignore this
part. I don't think workset is implemented in llvm. So I think it's OK
to ignore them for now too.

Dehao

On Wed, Sep 16, 2015 at 5:40 PM, Diego Novillo <dnovillo at google.com> wrote:
> Dehao,
>
> I'm not sure how important it is to support modules and working sets for
> LLVM's variant of AutoFDO.  I will be implementing the inline stack
> traversal support in the next few patches.  Do you think we'll need the
> other two?
>
>
> Thanks.
>
> On Wed, Sep 16, 2015 at 8:17 PM, Diego Novillo via llvm-commits
> <llvm-commits at lists.llvm.org> wrote:
>>
>> Author: dnovillo
>> Date: Wed Sep 16 19:17:24 2015
>> New Revision: 247874
>>
>> URL: http://llvm.org/viewvc/llvm-project?rev=247874&view=rev
>> Log:
>> GCC AutoFDO profile reader - Initial support.
>>
>> This adds enough machinery to support reading simple GCC AutoFDO
>> profiles. It now supports reading flat profiles (no function calls).
>> Subsequent patches will add support for:
>>
>> - Inlined calls (in particular, the inline call stack is not traversed
>>   to accumulate samples).
>>
>> - Working sets and modules. These are used mostly for GCC's LIPO
>>   optimizations, so they're not needed in LLVM atm. I'm not sure that
>>   we will ever need them. For now, I've if0'd around the calls.
>>
>> The patch also adds support in GCOV.h for gcov version V704 (generated
>> by GCC's profile conversion tool).
>>
>> Added:
>>     llvm/trunk/test/Transforms/SampleProfile/Inputs/gcc-simple.afdo
>>     llvm/trunk/test/Transforms/SampleProfile/gcc-simple.ll
>> Modified:
>>     llvm/trunk/include/llvm/ProfileData/SampleProf.h
>>     llvm/trunk/include/llvm/ProfileData/SampleProfReader.h
>>     llvm/trunk/include/llvm/Support/GCOV.h
>>     llvm/trunk/lib/ProfileData/SampleProf.cpp
>>     llvm/trunk/lib/ProfileData/SampleProfReader.cpp
>>
>> Modified: llvm/trunk/include/llvm/ProfileData/SampleProf.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/SampleProf.h?rev=247874&r1=247873&r2=247874&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/ProfileData/SampleProf.h (original)
>> +++ llvm/trunk/include/llvm/ProfileData/SampleProf.h Wed Sep 16 19:17:24
>> 2015
>> @@ -32,7 +32,8 @@ enum class sampleprof_error {
>>    too_large,
>>    truncated,
>>    malformed,
>> -  unrecognized_format
>> +  unrecognized_format,
>> +  not_implemented
>>  };
>>
>>  inline std::error_code make_error_code(sampleprof_error E) {
>>
>> Modified: llvm/trunk/include/llvm/ProfileData/SampleProfReader.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/SampleProfReader.h?rev=247874&r1=247873&r2=247874&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/ProfileData/SampleProfReader.h (original)
>> +++ llvm/trunk/include/llvm/ProfileData/SampleProfReader.h Wed Sep 16
>> 19:17:24 2015
>> @@ -24,6 +24,7 @@
>>  #include "llvm/Support/Debug.h"
>>  #include "llvm/Support/ErrorHandling.h"
>>  #include "llvm/Support/ErrorOr.h"
>> +#include "llvm/Support/GCOV.h"
>>  #include "llvm/Support/MemoryBuffer.h"
>>  #include "llvm/Support/raw_ostream.h"
>>
>> @@ -57,7 +58,7 @@ namespace sampleprof {
>>  ///
>>  /// The reader supports two file formats: text and binary. The text
>> format
>>  /// is useful for debugging and testing, while the binary format is more
>> -/// compact. They can both be used interchangeably.
>> +/// compact and I/O efficient. They can both be used interchangeably.
>>  class SampleProfileReader {
>>  public:
>>    SampleProfileReader(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
>> @@ -86,7 +87,7 @@ public:
>>    StringMap<FunctionSamples> &getProfiles() { return Profiles; }
>>
>>    /// \brief Report a parse error message.
>> -  void reportParseError(int64_t LineNumber, Twine Msg) const {
>> +  void reportError(int64_t LineNumber, Twine Msg) const {
>>
>> Ctx.diagnose(DiagnosticInfoSampleProfile(Buffer->getBufferIdentifier(),
>>                                               LineNumber, Msg));
>>    }
>> @@ -163,6 +164,86 @@ protected:
>>    const uint8_t *End;
>>  };
>>
>> +// Represents the source position in GCC sample profiles.
>> +struct SourceInfo {
>> +  SourceInfo()
>> +      : FuncName(), DirName(), FileName(), StartLine(0), Line(0),
>> +        Discriminator(0) {}
>> +
>> +  SourceInfo(StringRef FuncName, StringRef DirName, StringRef FileName,
>> +             uint32_t StartLine, uint32_t Line, uint32_t Discriminator)
>> +      : FuncName(FuncName), DirName(DirName), FileName(FileName),
>> +        StartLine(StartLine), Line(Line), Discriminator(Discriminator) {}
>> +
>> +  bool operator<(const SourceInfo &p) const;
>> +
>> +  uint32_t Offset() const { return ((Line - StartLine) << 16) |
>> Discriminator; }
>> +
>> +  bool Malformed() const { return Line < StartLine; }
>> +
>> +  StringRef FuncName;
>> +  StringRef DirName;
>> +  StringRef FileName;
>> +  uint32_t StartLine;
>> +  uint32_t Line;
>> +  uint32_t Discriminator;
>> +};
>> +
>> +typedef std::vector<SourceInfo> SourceStack;
>> +
>> +// Supported histogram types in GCC.  Currently, we only need support for
>> +// call target histograms.
>> +enum HistType {
>> +  HIST_TYPE_INTERVAL,
>> +  HIST_TYPE_POW2,
>> +  HIST_TYPE_SINGLE_VALUE,
>> +  HIST_TYPE_CONST_DELTA,
>> +  HIST_TYPE_INDIR_CALL,
>> +  HIST_TYPE_AVERAGE,
>> +  HIST_TYPE_IOR,
>> +  HIST_TYPE_INDIR_CALL_TOPN
>> +};
>> +
>> +class SampleProfileReaderGCC : public SampleProfileReader {
>> +public:
>> +  SampleProfileReaderGCC(std::unique_ptr<MemoryBuffer> B, LLVMContext &C)
>> +      : SampleProfileReader(std::move(B), C), GcovBuffer(Buffer.get()) {}
>> +
>> +  /// \brief Read and validate the file header.
>> +  std::error_code readHeader() override;
>> +
>> +  /// \brief Read sample profiles from the associated file.
>> +  std::error_code read() override;
>> +
>> +  /// \brief Return true if \p Buffer is in the format supported by this
>> class.
>> +  static bool hasFormat(const MemoryBuffer &Buffer);
>> +
>> +protected:
>> +  std::error_code readNameTable();
>> +  std::error_code addSourceCount(StringRef Name, const SourceStack &Src,
>> +                                 uint64_t Count);
>> +  std::error_code readOneFunctionProfile(const SourceStack &Stack, bool
>> Update);
>> +  std::error_code readFunctionProfiles();
>> +  std::error_code readModuleGroup();
>> +  std::error_code readWorkingSet();
>> +  std::error_code skipNextWord();
>> +  template <typename T> ErrorOr<T> readNumber();
>> +  ErrorOr<StringRef> readString();
>> +
>> +  /// \brief Read the section tag and check that it's the same as \p
>> Expected.
>> +  std::error_code readSectionTag(uint32_t Expected);
>> +
>> +  /// GCOV buffer containing the profile.
>> +  GCOVBuffer GcovBuffer;
>> +
>> +  /// Function names in this profile.
>> +  std::vector<std::string> Names;
>> +
>> +  /// GCOV tags used to separate sections in the profile file.
>> +  static const uint32_t GCOVTagAFDOFileNames = 0xaa000000;
>> +  static const uint32_t GCOVTagAFDOFunction = 0xac000000;
>> +};
>> +
>>  } // End namespace sampleprof
>>
>>  } // End namespace llvm
>>
>> Modified: llvm/trunk/include/llvm/Support/GCOV.h
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/GCOV.h?rev=247874&r1=247873&r2=247874&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/include/llvm/Support/GCOV.h (original)
>> +++ llvm/trunk/include/llvm/Support/GCOV.h Wed Sep 16 19:17:24 2015
>> @@ -30,7 +30,7 @@ class GCOVBlock;
>>  class FileInfo;
>>
>>  namespace GCOV {
>> -enum GCOVVersion { V402, V404 };
>> +enum GCOVVersion { V402, V404, V704 };
>>  } // end GCOV namespace
>>
>>  /// GCOVOptions - A struct for passing gcov options between functions.
>> @@ -90,6 +90,11 @@ public:
>>        Version = GCOV::V404;
>>        return true;
>>      }
>> +    if (VersionStr == "*704") {
>> +      Cursor += 4;
>> +      Version = GCOV::V704;
>> +      return true;
>> +    }
>>      errs() << "Unexpected version: " << VersionStr << ".\n";
>>      return false;
>>    }
>>
>> Modified: llvm/trunk/lib/ProfileData/SampleProf.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/SampleProf.cpp?rev=247874&r1=247873&r2=247874&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/ProfileData/SampleProf.cpp (original)
>> +++ llvm/trunk/lib/ProfileData/SampleProf.cpp Wed Sep 16 19:17:24 2015
>> @@ -38,6 +38,8 @@ class SampleProfErrorCategoryType : publ
>>        return "Malformed profile data";
>>      case sampleprof_error::unrecognized_format:
>>        return "Unrecognized profile encoding format";
>> +    case sampleprof_error::not_implemented:
>> +      return "Unimplemented feature";
>>      }
>>      llvm_unreachable("A value of sampleprof_error has no message.");
>>    }
>>
>> Modified: llvm/trunk/lib/ProfileData/SampleProfReader.cpp
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/SampleProfReader.cpp?rev=247874&r1=247873&r2=247874&view=diff
>>
>> ==============================================================================
>> --- llvm/trunk/lib/ProfileData/SampleProfReader.cpp (original)
>> +++ llvm/trunk/lib/ProfileData/SampleProfReader.cpp Wed Sep 16 19:17:24
>> 2015
>> @@ -173,8 +173,8 @@ std::error_code SampleProfileReaderText:
>>      // should not begin with a number.
>>      SmallVector<StringRef, 4> Matches;
>>      if (!HeadRE.match(*LineIt, &Matches)) {
>> -      reportParseError(LineIt.line_number(),
>> -                       "Expected 'mangled_name:NUM:NUM', found " +
>> *LineIt);
>> +      reportError(LineIt.line_number(),
>> +                  "Expected 'mangled_name:NUM:NUM', found " + *LineIt);
>>        return sampleprof_error::malformed;
>>      }
>>      assert(Matches.size() == 4);
>> @@ -192,9 +192,9 @@ std::error_code SampleProfileReaderText:
>>      // EOF or when we see the start of the next function.
>>      while (!LineIt.is_at_eof() && isdigit((*LineIt)[0])) {
>>        if (!LineSampleRE.match(*LineIt, &Matches)) {
>> -        reportParseError(
>> -            LineIt.line_number(),
>> -            "Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found " +
>> *LineIt);
>> +        reportError(LineIt.line_number(),
>> +                    "Expected 'NUM[.NUM]: NUM[ mangled_name:NUM]*', found
>> " +
>> +                        *LineIt);
>>          return sampleprof_error::malformed;
>>        }
>>        assert(Matches.size() == 5);
>> @@ -210,8 +210,8 @@ std::error_code SampleProfileReaderText:
>>        while (CallsLine != "") {
>>          SmallVector<StringRef, 3> CallSample;
>>          if (!CallSampleRE.match(CallsLine, &CallSample)) {
>> -          reportParseError(LineIt.line_number(),
>> -                           "Expected 'mangled_name:NUM', found " +
>> CallsLine);
>> +          reportError(LineIt.line_number(),
>> +                      "Expected 'mangled_name:NUM', found " + CallsLine);
>>            return sampleprof_error::malformed;
>>          }
>>          StringRef CalledFunction = CallSample[1];
>> @@ -243,7 +243,7 @@ template <typename T> ErrorOr<T> SampleP
>>      EC = sampleprof_error::success;
>>
>>    if (EC) {
>> -    reportParseError(0, EC.message());
>> +    reportError(0, EC.message());
>>      return EC;
>>    }
>>
>> @@ -256,7 +256,7 @@ ErrorOr<StringRef> SampleProfileReaderBi
>>    StringRef Str(reinterpret_cast<const char *>(Data));
>>    if (Data + Str.size() + 1 > End) {
>>      EC = sampleprof_error::truncated;
>> -    reportParseError(0, EC.message());
>> +    reportError(0, EC.message());
>>      return EC;
>>    }
>>
>> @@ -353,6 +353,264 @@ bool SampleProfileReaderBinary::hasForma
>>    return Magic == SPMagic();
>>  }
>>
>> +bool SourceInfo::operator<(const SourceInfo &P) const {
>> +  if (Line != P.Line)
>> +    return Line < P.Line;
>> +  if (StartLine != P.StartLine)
>> +    return StartLine < P.StartLine;
>> +  if (Discriminator != P.Discriminator)
>> +    return Discriminator < P.Discriminator;
>> +  return FuncName < P.FuncName;
>> +}
>> +
>> +std::error_code SampleProfileReaderGCC::skipNextWord() {
>> +  uint32_t dummy;
>> +  if (!GcovBuffer.readInt(dummy))
>> +    return sampleprof_error::truncated;
>> +  return sampleprof_error::success;
>> +}
>> +
>> +template <typename T> ErrorOr<T> SampleProfileReaderGCC::readNumber() {
>> +  if (sizeof(T) <= sizeof(uint32_t)) {
>> +    uint32_t Val;
>> +    if (GcovBuffer.readInt(Val) && Val <= std::numeric_limits<T>::max())
>> +      return static_cast<T>(Val);
>> +  } else if (sizeof(T) <= sizeof(uint64_t)) {
>> +    uint64_t Val;
>> +    if (GcovBuffer.readInt64(Val) && Val <=
>> std::numeric_limits<T>::max())
>> +      return static_cast<T>(Val);
>> +  }
>> +
>> +  std::error_code EC = sampleprof_error::malformed;
>> +  reportError(0, EC.message());
>> +  return EC;
>> +}
>> +
>> +ErrorOr<StringRef> SampleProfileReaderGCC::readString() {
>> +  StringRef Str;
>> +  if (!GcovBuffer.readString(Str))
>> +    return sampleprof_error::truncated;
>> +  return Str;
>> +}
>> +
>> +std::error_code SampleProfileReaderGCC::readHeader() {
>> +  // Read the magic identifier.
>> +  if (!GcovBuffer.readGCDAFormat())
>> +    return sampleprof_error::unrecognized_format;
>> +
>> +  // Read the version number. Note - the GCC reader does not validate
>> this
>> +  // version, but the profile creator generates v704.
>> +  GCOV::GCOVVersion version;
>> +  if (!GcovBuffer.readGCOVVersion(version))
>> +    return sampleprof_error::unrecognized_format;
>> +
>> +  if (version != GCOV::V704)
>> +    return sampleprof_error::unsupported_version;
>> +
>> +  // Skip the empty integer.
>> +  if (std::error_code EC = skipNextWord())
>> +    return EC;
>> +
>> +  return sampleprof_error::success;
>> +}
>> +
>> +std::error_code SampleProfileReaderGCC::readSectionTag(uint32_t Expected)
>> {
>> +  uint32_t Tag;
>> +  if (!GcovBuffer.readInt(Tag))
>> +    return sampleprof_error::truncated;
>> +
>> +  if (Tag != Expected)
>> +    return sampleprof_error::malformed;
>> +
>> +  if (std::error_code EC = skipNextWord())
>> +    return EC;
>> +
>> +  return sampleprof_error::success;
>> +}
>> +
>> +std::error_code SampleProfileReaderGCC::readNameTable() {
>> +  if (std::error_code EC = readSectionTag(GCOVTagAFDOFileNames))
>> +    return EC;
>> +
>> +  uint32_t Size;
>> +  if (!GcovBuffer.readInt(Size))
>> +    return sampleprof_error::truncated;
>> +
>> +  for (uint32_t I = 0; I < Size; ++I) {
>> +    StringRef Str;
>> +    if (!GcovBuffer.readString(Str))
>> +      return sampleprof_error::truncated;
>> +    Names.push_back(Str);
>> +  }
>> +
>> +  return sampleprof_error::success;
>> +}
>> +
>> +std::error_code SampleProfileReaderGCC::readFunctionProfiles() {
>> +  if (std::error_code EC = readSectionTag(GCOVTagAFDOFunction))
>> +    return EC;
>> +
>> +  uint32_t NumFunctions;
>> +  if (!GcovBuffer.readInt(NumFunctions))
>> +    return sampleprof_error::truncated;
>> +
>> +  SourceStack Stack;
>> +  for (uint32_t I = 0; I < NumFunctions; ++I)
>> +    if (std::error_code EC = readOneFunctionProfile(Stack, true))
>> +      return EC;
>> +
>> +  return sampleprof_error::success;
>> +}
>> +
>> +std::error_code SampleProfileReaderGCC::addSourceCount(StringRef Name,
>> +                                                       const SourceStack
>> &Src,
>> +                                                       uint64_t Count) {
>> +  if (Src.size() == 0 || Src[0].Malformed())
>> +    return sampleprof_error::malformed;
>> +  FunctionSamples &FProfile = Profiles[Name];
>> +  FProfile.addTotalSamples(Count);
>> +  // FIXME(dnovillo) - Properly update inline stack for FnName.
>> +  FProfile.addBodySamples(Src[0].Line, Src[0].Discriminator, Count);
>> +  return sampleprof_error::success;
>> +}
>> +
>> +
>> +std::error_code
>> +SampleProfileReaderGCC::readOneFunctionProfile(const SourceStack &Stack,
>> +                                               bool Update) {
>> +  uint64_t HeadCount = 0;
>> +  if (Stack.size() == 0)
>> +    if (!GcovBuffer.readInt64(HeadCount))
>> +      return sampleprof_error::truncated;
>> +
>> +  uint32_t NameIdx;
>> +  if (!GcovBuffer.readInt(NameIdx))
>> +    return sampleprof_error::truncated;
>> +
>> +  StringRef Name(Names[NameIdx]);
>> +
>> +  uint32_t NumPosCounts;
>> +  if (!GcovBuffer.readInt(NumPosCounts))
>> +    return sampleprof_error::truncated;
>> +
>> +  uint32_t NumCallSites;
>> +  if (!GcovBuffer.readInt(NumCallSites))
>> +    return sampleprof_error::truncated;
>> +
>> +  if (Stack.size() == 0) {
>> +    FunctionSamples &FProfile = Profiles[Name];
>> +    FProfile.addHeadSamples(HeadCount);
>> +    if (FProfile.getTotalSamples() > 0)
>> +      Update = false;
>> +  }
>> +
>> +  for (uint32_t I = 0; I < NumPosCounts; ++I) {
>> +    uint32_t Offset;
>> +    if (!GcovBuffer.readInt(Offset))
>> +      return sampleprof_error::truncated;
>> +
>> +    uint32_t NumTargets;
>> +    if (!GcovBuffer.readInt(NumTargets))
>> +      return sampleprof_error::truncated;
>> +
>> +    uint64_t Count;
>> +    if (!GcovBuffer.readInt64(Count))
>> +      return sampleprof_error::truncated;
>> +
>> +    SourceInfo Info(Name, "", "", 0, Offset >> 16, Offset & 0xffff);
>> +    SourceStack NewStack;
>> +    NewStack.push_back(Info);
>> +    NewStack.insert(NewStack.end(), Stack.begin(), Stack.end());
>> +    if (Update)
>> +      addSourceCount(NewStack[NewStack.size() - 1].FuncName, NewStack,
>> Count);
>> +
>> +    for (uint32_t J = 0; J < NumTargets; J++) {
>> +      uint32_t HistVal;
>> +      if (!GcovBuffer.readInt(HistVal))
>> +        return sampleprof_error::truncated;
>> +
>> +      if (HistVal != HIST_TYPE_INDIR_CALL_TOPN)
>> +        return sampleprof_error::malformed;
>> +
>> +      uint64_t TargetIdx;
>> +      if (!GcovBuffer.readInt64(TargetIdx))
>> +        return sampleprof_error::truncated;
>> +      StringRef TargetName(Names[TargetIdx]);
>> +
>> +      uint64_t TargetCount;
>> +      if (!GcovBuffer.readInt64(TargetCount))
>> +        return sampleprof_error::truncated;
>> +
>> +      if (Update) {
>> +        FunctionSamples &TargetProfile = Profiles[TargetName];
>> +        TargetProfile.addBodySamples(NewStack[0].Line,
>> +                                     NewStack[0].Discriminator,
>> TargetCount);
>> +      }
>> +    }
>> +  }
>> +
>> +  for (uint32_t I = 0; I < NumCallSites; I++) {
>> +    // The offset is encoded as:
>> +    //   high 16 bits: line offset to the start of the function.
>> +    //   low 16 bits: discriminator.
>> +    uint32_t Offset;
>> +    if (!GcovBuffer.readInt(Offset))
>> +      return sampleprof_error::truncated;
>> +    SourceInfo Info(Name, "", "", 0, Offset >> 16, Offset & 0xffff);
>> +    SourceStack NewStack;
>> +    NewStack.push_back(Info);
>> +    NewStack.insert(NewStack.end(), Stack.begin(), Stack.end());
>> +    if (std::error_code EC = readOneFunctionProfile(NewStack, Update))
>> +      return EC;
>> +  }
>> +
>> +  return sampleprof_error::success;
>> +}
>> +
>> +std::error_code SampleProfileReaderGCC::readModuleGroup() {
>> +  // FIXME(dnovillo) - Module support still not implemented.
>> +  return sampleprof_error::not_implemented;
>> +}
>> +
>> +std::error_code SampleProfileReaderGCC::readWorkingSet() {
>> +  // FIXME(dnovillo) - Working sets still not implemented.
>> +  return sampleprof_error::not_implemented;
>> +}
>> +
>> +
>> +/// \brief Read a GCC AutoFDO profile.
>> +///
>> +/// This format is generated by the Linux Perf conversion tool at
>> +/// https://github.com/google/autofdo.
>> +std::error_code SampleProfileReaderGCC::read() {
>> +  // Read the string table.
>> +  if (std::error_code EC = readNameTable())
>> +    return EC;
>> +
>> +  // Read the source profile.
>> +  if (std::error_code EC = readFunctionProfiles())
>> +    return EC;
>> +
>> +  // FIXME(dnovillo) - Module groups and working set support are not
>> +  // yet implemented.
>> +#if 0
>> +  // Read the module group file.
>> +  if (std::error_code EC = readModuleGroup())
>> +    return EC;
>> +
>> +  // Read the working set.
>> +  if (std::error_code EC = readWorkingSet())
>> +    return EC;
>> +#endif
>> +
>> +  return sampleprof_error::success;
>> +}
>> +
>> +bool SampleProfileReaderGCC::hasFormat(const MemoryBuffer &Buffer) {
>> +  StringRef Magic(reinterpret_cast<const char
>> *>(Buffer.getBufferStart()));
>> +  return Magic == "adcg*704";
>> +}
>> +
>>  /// \brief Prepare a memory buffer for the contents of \p Filename.
>>  ///
>>  /// \returns an error code indicating the status of the buffer.
>> @@ -389,6 +647,8 @@ SampleProfileReader::create(StringRef Fi
>>    std::unique_ptr<SampleProfileReader> Reader;
>>    if (SampleProfileReaderBinary::hasFormat(*Buffer))
>>      Reader.reset(new SampleProfileReaderBinary(std::move(Buffer), C));
>> +  else if (SampleProfileReaderGCC::hasFormat(*Buffer))
>> +    Reader.reset(new SampleProfileReaderGCC(std::move(Buffer), C));
>>    else
>>      Reader.reset(new SampleProfileReaderText(std::move(Buffer), C));
>>
>>
>> Added: llvm/trunk/test/Transforms/SampleProfile/Inputs/gcc-simple.afdo
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SampleProfile/Inputs/gcc-simple.afdo?rev=247874&view=auto
>>
>> ==============================================================================
>> Binary files
>> llvm/trunk/test/Transforms/SampleProfile/Inputs/gcc-simple.afdo (added) and
>> llvm/trunk/test/Transforms/SampleProfile/Inputs/gcc-simple.afdo Wed Sep 16
>> 19:17:24 2015 differ
>>
>> Added: llvm/trunk/test/Transforms/SampleProfile/gcc-simple.ll
>> URL:
>> http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SampleProfile/gcc-simple.ll?rev=247874&view=auto
>>
>> ==============================================================================
>> --- llvm/trunk/test/Transforms/SampleProfile/gcc-simple.ll (added)
>> +++ llvm/trunk/test/Transforms/SampleProfile/gcc-simple.ll Wed Sep 16
>> 19:17:24 2015
>> @@ -0,0 +1,218 @@
>> +; RUN: opt < %s -sample-profile
>> -sample-profile-file=%S/Inputs/gcc-simple.afdo -S | FileCheck %s
>> +;
>> +; Original code:
>> +;
>> +; #include <stdlib.h>
>> +;
>> +; long long int foo(long i) {
>> +;   if (rand() < 500) return 2; else if (rand() > 5000) return 10; else
>> return 90;
>> +; }
>> +;
>> +; int main() {
>> +;   long long int sum = 0;
>> +;   for (int k = 0; k < 3000; k++)
>> +;     for (int i = 0; i < 200000; i++) sum += foo(i);
>> +;   return sum > 0 ? 0 : 1;
>> +; }
>> +;
>> +; This test was compiled down to bytecode at -O0 to avoid inlining foo()
>> into
>> +; main(). The profile was generated using a GCC-generated binary (also
>> compiled
>> +; at -O0). The conversion from the Linux Perf profile to the GCC autofdo
>> +; profile used the converter at https://github.com/google/autofdo
>> +;
>> +; $ gcc -g -O0 gcc-simple.cc -o gcc-simple
>> +; $ perf record -b ./gcc-simple
>> +; $ create_gcov --binary=gcc-simple --gcov=gcc-simple.afdo
>> +
>> +define i64 @_Z3fool(i64 %i) #0 {
>> +; CHECK: !prof ![[EC1:[0-9]+]]
>> +entry:
>> +  %retval = alloca i64, align 8
>> +  %i.addr = alloca i64, align 8
>> +  store i64 %i, i64* %i.addr, align 8
>> +  call void @llvm.dbg.declare(metadata i64* %i.addr, metadata !16,
>> metadata !17), !dbg !18
>> +  %call = call i32 @rand() #3, !dbg !19
>> +  %cmp = icmp slt i32 %call, 500, !dbg !21
>> +  br i1 %cmp, label %if.then, label %if.else, !dbg !22
>> +; CHECK: !prof ![[PROF1:[0-9]+]]
>> +
>> +if.then:                                          ; preds = %entry
>> +  store i64 2, i64* %retval, align 8, !dbg !23
>> +  br label %return, !dbg !23
>> +
>> +if.else:                                          ; preds = %entry
>> +  %call1 = call i32 @rand() #3, !dbg !25
>> +  %cmp2 = icmp sgt i32 %call1, 5000, !dbg !28
>> +  br i1 %cmp2, label %if.then.3, label %if.else.4, !dbg !29
>> +; CHECK: !prof ![[PROF2:[0-9]+]]
>> +
>> +if.then.3:                                        ; preds = %if.else
>> +  store i64 10, i64* %retval, align 8, !dbg !30
>> +  br label %return, !dbg !30
>> +
>> +if.else.4:                                        ; preds = %if.else
>> +  store i64 90, i64* %retval, align 8, !dbg !32
>> +  br label %return, !dbg !32
>> +
>> +return:                                           ; preds = %if.else.4,
>> %if.then.3, %if.then
>> +  %0 = load i64, i64* %retval, align 8, !dbg !34
>> +  ret i64 %0, !dbg !34
>> +}
>> +
>> +; Function Attrs: nounwind readnone
>> +declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
>> +
>> +; Function Attrs: nounwind
>> +declare i32 @rand() #2
>> +
>> +; Function Attrs: nounwind uwtable
>> +define i32 @main() #0 {
>> +; CHECK: !prof ![[EC2:[0-9]+]]
>> +entry:
>> +  %retval = alloca i32, align 4
>> +  %sum = alloca i64, align 8
>> +  %k = alloca i32, align 4
>> +  %i = alloca i32, align 4
>> +  store i32 0, i32* %retval, align 4
>> +  call void @llvm.dbg.declare(metadata i64* %sum, metadata !35, metadata
>> !17), !dbg !36
>> +  store i64 0, i64* %sum, align 8, !dbg !36
>> +  call void @llvm.dbg.declare(metadata i32* %k, metadata !37, metadata
>> !17), !dbg !39
>> +  store i32 0, i32* %k, align 4, !dbg !39
>> +  br label %for.cond, !dbg !40
>> +
>> +for.cond:                                         ; preds = %for.inc.4,
>> %entry
>> +  %0 = load i32, i32* %k, align 4, !dbg !41
>> +  %cmp = icmp slt i32 %0, 3000, !dbg !45
>> +  br i1 %cmp, label %for.body, label %for.end.6, !dbg !46
>> +; CHECK: !prof ![[PROF3:[0-9]+]]
>> +
>> +for.body:                                         ; preds = %for.cond
>> +  call void @llvm.dbg.declare(metadata i32* %i, metadata !47, metadata
>> !17), !dbg !49
>> +  store i32 0, i32* %i, align 4, !dbg !49
>> +  br label %for.cond.1, !dbg !50
>> +
>> +for.cond.1:                                       ; preds = %for.inc,
>> %for.body
>> +  %1 = load i32, i32* %i, align 4, !dbg !51
>> +  %cmp2 = icmp slt i32 %1, 200000, !dbg !55
>> +  br i1 %cmp2, label %for.body.3, label %for.end, !dbg !56
>> +; CHECK: !prof ![[PROF4:[0-9]+]]
>> +
>> +for.body.3:                                       ; preds = %for.cond.1
>> +  %2 = load i32, i32* %i, align 4, !dbg !57
>> +  %conv = sext i32 %2 to i64, !dbg !57
>> +  %call = call i64 @_Z3fool(i64 %conv), !dbg !59
>> +  %3 = load i64, i64* %sum, align 8, !dbg !60
>> +  %add = add nsw i64 %3, %call, !dbg !60
>> +  store i64 %add, i64* %sum, align 8, !dbg !60
>> +  br label %for.inc, !dbg !61
>> +
>> +for.inc:                                          ; preds = %for.body.3
>> +  %4 = load i32, i32* %i, align 4, !dbg !62
>> +  %inc = add nsw i32 %4, 1, !dbg !62
>> +  store i32 %inc, i32* %i, align 4, !dbg !62
>> +  br label %for.cond.1, !dbg !64
>> +
>> +for.end:                                          ; preds = %for.cond.1
>> +  br label %for.inc.4, !dbg !65
>> +
>> +for.inc.4:                                        ; preds = %for.end
>> +  %5 = load i32, i32* %k, align 4, !dbg !67
>> +  %inc5 = add nsw i32 %5, 1, !dbg !67
>> +  store i32 %inc5, i32* %k, align 4, !dbg !67
>> +  br label %for.cond, !dbg !68
>> +
>> +for.end.6:                                        ; preds = %for.cond
>> +  %6 = load i64, i64* %sum, align 8, !dbg !69
>> +  %cmp7 = icmp sgt i64 %6, 0, !dbg !70
>> +  %cond = select i1 %cmp7, i32 0, i32 1, !dbg !69
>> +  ret i32 %cond, !dbg !71
>> +}
>> +
>> +; CHECK ![[EC1]] = !{!"function_entry_count", i64 24108}
>> +; CHECK ![[PROF1]] = !{!"branch_weights", i32 1, i32 30124}
>> +; CHECK ![[PROF2]] = !{!"branch_weights", i32 30177, i32 29579}
>> +; CHECK ![[EC2]] = !{!"function_entry_count", i64 0}
>> +; CHECK ![[PROF3]] = !{!"branch_weights", i32 1, i32 1}
>> +; CHECK ![[PROF4]] = !{!"branch_weights", i32 1, i32 20238}
>> +
>> +attributes #0 = { nounwind uwtable "disable-tail-calls"="false"
>> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
>> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
>> "no-nans-fp-math"="false" "stack-protector-buffer-size"="8"
>> "target-cpu"="x86-64" "target-features"="+sse,+sse2"
>> "unsafe-fp-math"="false" "use-soft-float"="false" }
>> +attributes #1 = { nounwind readnone }
>> +attributes #2 = { nounwind "disable-tail-calls"="false"
>> "less-precise-fpmad"="false" "no-frame-pointer-elim"="true"
>> "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false"
>> "no-nans-fp-math"="false" "stack-protector-buffer-size"="8"
>> "target-cpu"="x86-64" "target-features"="+sse,+sse2"
>> "unsafe-fp-math"="false" "use-soft-float"="false" }
>> +attributes #3 = { nounwind }
>> +
>> +!llvm.dbg.cu = !{!0}
>> +!llvm.module.flags = !{!13, !14}
>> +!llvm.ident = !{!15}
>> +
>> +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1,
>> producer: "clang version 3.8.0 (trunk 247554) (llvm/trunk 247557)",
>> isOptimized: false, runtimeVersion: 0, emissionKind: 1, enums: !2,
>> subprograms: !3)
>> +!1 = !DIFile(filename: "discriminator.cc", directory:
>> "/usr/local/google/home/dnovillo/llvm/test/autofdo")
>> +!2 = !{}
>> +!3 = !{!4, !9}
>> +!4 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fool", scope:
>> !1, file: !1, line: 3, type: !5, isLocal: false, isDefinition: true,
>> scopeLine: 3, flags: DIFlagPrototyped, isOptimized: false, function: i64
>> (i64)* @_Z3fool, variables: !2)
>> +!5 = !DISubroutineType(types: !6)
>> +!6 = !{!7, !8}
>> +!7 = !DIBasicType(name: "long long int", size: 64, align: 64, encoding:
>> DW_ATE_signed)
>> +!8 = !DIBasicType(name: "long int", size: 64, align: 64, encoding:
>> DW_ATE_signed)
>> +!9 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 7,
>> type: !10, isLocal: false, isDefinition: true, scopeLine: 7, flags:
>> DIFlagPrototyped, isOptimized: false, function: i32 ()* @main, variables:
>> !2)
>> +!10 = !DISubroutineType(types: !11)
>> +!11 = !{!12}
>> +!12 = !DIBasicType(name: "int", size: 32, align: 32, encoding:
>> DW_ATE_signed)
>> +!13 = !{i32 2, !"Dwarf Version", i32 4}
>> +!14 = !{i32 2, !"Debug Info Version", i32 3}
>> +!15 = !{!"clang version 3.8.0 (trunk 247554) (llvm/trunk 247557)"}
>> +!16 = !DILocalVariable(name: "i", arg: 1, scope: !4, file: !1, line: 3,
>> type: !8)
>> +!17 = !DIExpression()
>> +!18 = !DILocation(line: 3, column: 24, scope: !4)
>> +!19 = !DILocation(line: 4, column: 7, scope: !20)
>> +!20 = distinct !DILexicalBlock(scope: !4, file: !1, line: 4, column: 7)
>> +!21 = !DILocation(line: 4, column: 14, scope: !20)
>> +!22 = !DILocation(line: 4, column: 7, scope: !4)
>> +!23 = !DILocation(line: 4, column: 21, scope: !24)
>> +!24 = !DILexicalBlockFile(scope: !20, file: !1, discriminator: 1)
>> +!25 = !DILocation(line: 4, column: 40, scope: !26)
>> +!26 = !DILexicalBlockFile(scope: !27, file: !1, discriminator: 2)
>> +!27 = distinct !DILexicalBlock(scope: !20, file: !1, line: 4, column: 40)
>> +!28 = !DILocation(line: 4, column: 47, scope: !27)
>> +!29 = !DILocation(line: 4, column: 40, scope: !20)
>> +!30 = !DILocation(line: 4, column: 55, scope: !31)
>> +!31 = !DILexicalBlockFile(scope: !27, file: !1, discriminator: 3)
>> +!32 = !DILocation(line: 4, column: 71, scope: !33)
>> +!33 = !DILexicalBlockFile(scope: !27, file: !1, discriminator: 4)
>> +!34 = !DILocation(line: 5, column: 1, scope: !4)
>> +!35 = !DILocalVariable(name: "sum", scope: !9, file: !1, line: 8, type:
>> !7)
>> +!36 = !DILocation(line: 8, column: 17, scope: !9)
>> +!37 = !DILocalVariable(name: "k", scope: !38, file: !1, line: 9, type:
>> !12)
>> +!38 = distinct !DILexicalBlock(scope: !9, file: !1, line: 9, column: 3)
>> +!39 = !DILocation(line: 9, column: 12, scope: !38)
>> +!40 = !DILocation(line: 9, column: 8, scope: !38)
>> +!41 = !DILocation(line: 9, column: 19, scope: !42)
>> +!42 = !DILexicalBlockFile(scope: !43, file: !1, discriminator: 2)
>> +!43 = !DILexicalBlockFile(scope: !44, file: !1, discriminator: 1)
>> +!44 = distinct !DILexicalBlock(scope: !38, file: !1, line: 9, column: 3)
>> +!45 = !DILocation(line: 9, column: 21, scope: !44)
>> +!46 = !DILocation(line: 9, column: 3, scope: !38)
>> +!47 = !DILocalVariable(name: "i", scope: !48, file: !1, line: 10, type:
>> !12)
>> +!48 = distinct !DILexicalBlock(scope: !44, file: !1, line: 10, column: 5)
>> +!49 = !DILocation(line: 10, column: 14, scope: !48)
>> +!50 = !DILocation(line: 10, column: 10, scope: !48)
>> +!51 = !DILocation(line: 10, column: 21, scope: !52)
>> +!52 = !DILexicalBlockFile(scope: !53, file: !1, discriminator: 5)
>> +!53 = !DILexicalBlockFile(scope: !54, file: !1, discriminator: 1)
>> +!54 = distinct !DILexicalBlock(scope: !48, file: !1, line: 10, column: 5)
>> +!55 = !DILocation(line: 10, column: 23, scope: !54)
>> +!56 = !DILocation(line: 10, column: 5, scope: !48)
>> +!57 = !DILocation(line: 10, column: 49, scope: !58)
>> +!58 = !DILexicalBlockFile(scope: !54, file: !1, discriminator: 2)
>> +!59 = !DILocation(line: 10, column: 45, scope: !54)
>> +!60 = !DILocation(line: 10, column: 42, scope: !54)
>> +!61 = !DILocation(line: 10, column: 38, scope: !54)
>> +!62 = !DILocation(line: 10, column: 34, scope: !63)
>> +!63 = !DILexicalBlockFile(scope: !54, file: !1, discriminator: 4)
>> +!64 = !DILocation(line: 10, column: 5, scope: !54)
>> +!65 = !DILocation(line: 10, column: 50, scope: !66)
>> +!66 = !DILexicalBlockFile(scope: !48, file: !1, discriminator: 3)
>> +!67 = !DILocation(line: 9, column: 30, scope: !44)
>> +!68 = !DILocation(line: 9, column: 3, scope: !44)
>> +!69 = !DILocation(line: 11, column: 10, scope: !9)
>> +!70 = !DILocation(line: 11, column: 14, scope: !9)
>> +!71 = !DILocation(line: 11, column: 3, scope: !9)
>>
>>
>> _______________________________________________
>> llvm-commits mailing list
>> llvm-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
>


More information about the llvm-commits mailing list