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

Diego Novillo via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 16 17:40:04 PDT 2015


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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20150916/480de953/attachment-0001.html>


More information about the llvm-commits mailing list