Merging r261258:
[oota-llvm.git] / lib / ProfileData / SampleProfReader.cpp
index 6149c6c3506b95835353fb2c344a60ae4e79f56b..93cd87bb82f8b554842d435c11c69fcd640f80b2 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "llvm/ProfileData/SampleProfReader.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/LEB128.h"
 #include "llvm/Support/LineIterator.h"
 #include "llvm/Support/MemoryBuffer.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallVector.h"
 
 using namespace llvm::sampleprof;
 using namespace llvm;
 
-/// \brief Print the samples collected for a function on stream \p OS.
-///
-/// \param OS Stream to emit the output to.
-void FunctionSamples::print(raw_ostream &OS, unsigned Indent) const {
-  OS << TotalSamples << ", " << TotalHeadSamples << ", " << BodySamples.size()
-     << " sampled lines\n";
-  for (const auto &SI : BodySamples) {
-    LineLocation Loc = SI.first;
-    const SampleRecord &Sample = SI.second;
-    OS.indent(Indent);
-    OS << "line offset: " << Loc.LineOffset
-       << ", discriminator: " << Loc.Discriminator
-       << ", number of samples: " << Sample.getSamples();
-    if (Sample.hasCalls()) {
-      OS << ", calls:";
-      for (const auto &I : Sample.getCallTargets())
-        OS << " " << I.first() << ":" << I.second;
-    }
-    OS << "\n";
-  }
-  for (const auto &CS : CallsiteSamples) {
-    CallsiteLocation Loc = CS.first;
-    const FunctionSamples &CalleeSamples = CS.second;
-    OS.indent(Indent);
-    OS << "line offset: " << Loc.LineOffset
-       << ", discriminator: " << Loc.Discriminator
-       << ", inlined callee: " << Loc.CalleeName << ": ";
-    CalleeSamples.print(OS, Indent + 2);
-  }
-}
-
 /// \brief Dump the function profile for \p FName.
 ///
 /// \param FName Name of the function to print.
 /// \param OS Stream to emit the output to.
 void SampleProfileReader::dumpFunctionProfile(StringRef FName,
                                               raw_ostream &OS) {
-  OS << "Function: " << FName << ": ";
-  Profiles[FName].print(OS);
+  OS << "Function: " << FName << ": " << Profiles[FName];
 }
 
 /// \brief Dump all the function profiles found on stream \p OS.
@@ -87,7 +55,7 @@ void SampleProfileReader::dump(raw_ostream &OS) {
 ///
 /// \returns true if parsing is successful.
 static bool ParseHead(const StringRef &Input, StringRef &FName,
-                      unsigned &NumSamples, unsigned &NumHeadSamples) {
+                      uint64_t &NumSamples, uint64_t &NumHeadSamples) {
   if (Input[0] == ' ')
     return false;
   size_t n2 = Input.rfind(':');
@@ -100,6 +68,12 @@ static bool ParseHead(const StringRef &Input, StringRef &FName,
   return true;
 }
 
+
+/// \brief Returns true if line offset \p L is legal (only has 16 bits).
+static bool isOffsetLegal(unsigned L) {
+  return (L & 0xffff) == L;
+}
+
 /// \brief Parse \p Input as line sample.
 ///
 /// \param Input input line.
@@ -111,10 +85,10 @@ static bool ParseHead(const StringRef &Input, StringRef &FName,
 /// \param TargetCountMap map from indirect call target to count.
 ///
 /// returns true if parsing is successful.
-static bool ParseLine(const StringRef &Input, bool &IsCallsite, unsigned &Depth,
-                      unsigned &NumSamples, unsigned &LineOffset,
-                      unsigned &Discriminator, StringRef &CalleeName,
-                      DenseMap<StringRef, unsigned> &TargetCountMap) {
+static bool ParseLine(const StringRef &Input, bool &IsCallsite, uint32_t &Depth,
+                      uint64_t &NumSamples, uint32_t &LineOffset,
+                      uint32_t &Discriminator, StringRef &CalleeName,
+                      DenseMap<StringRef, uint64_t> &TargetCountMap) {
   for (Depth = 0; Input[Depth] == ' '; Depth++)
     ;
   if (Depth == 0)
@@ -124,7 +98,7 @@ static bool ParseLine(const StringRef &Input, bool &IsCallsite, unsigned &Depth,
   StringRef Loc = Input.substr(Depth, n1 - Depth);
   size_t n2 = Loc.find('.');
   if (n2 == StringRef::npos) {
-    if (Loc.getAsInteger(10, LineOffset))
+    if (Loc.getAsInteger(10, LineOffset) || !isOffsetLegal(LineOffset))
       return false;
     Discriminator = 0;
   } else {
@@ -153,15 +127,15 @@ static bool ParseLine(const StringRef &Input, bool &IsCallsite, unsigned &Depth,
       if (n3 != StringRef::npos) {
         pair = Rest.substr(0, n3);
       }
-      int n4 = pair.find(':');
-      unsigned count;
+      size_t n4 = pair.find(':');
+      uint64_t count;
       if (pair.substr(n4 + 1).getAsInteger(10, count))
         return false;
       TargetCountMap[pair.substr(0, n4)] = count;
     }
   } else {
     IsCallsite = true;
-    int n3 = Rest.find_last_of(':');
+    size_t n3 = Rest.find_last_of(':');
     CalleeName = Rest.substr(0, n3);
     if (Rest.substr(n3 + 1).getAsInteger(10, NumSamples))
       return false;
@@ -177,6 +151,7 @@ static bool ParseLine(const StringRef &Input, bool &IsCallsite, unsigned &Depth,
 /// \returns true if the file was loaded successfully, false otherwise.
 std::error_code SampleProfileReaderText::read() {
   line_iterator LineIt(*Buffer, /*SkipBlanks=*/true, '#');
+  sampleprof_error Result = sampleprof_error::success;
 
   InlineCallStack InlineStack;
 
@@ -196,7 +171,7 @@ std::error_code SampleProfileReaderText::read() {
     // The only requirement we place on the identifier, then, is that it
     // should not begin with a number.
     if ((*LineIt)[0] != ' ') {
-      unsigned NumSamples, NumHeadSamples;
+      uint64_t NumSamples, NumHeadSamples;
       StringRef FName;
       if (!ParseHead(*LineIt, FName, NumSamples, NumHeadSamples)) {
         reportError(LineIt.line_number(),
@@ -205,16 +180,16 @@ std::error_code SampleProfileReaderText::read() {
       }
       Profiles[FName] = FunctionSamples();
       FunctionSamples &FProfile = Profiles[FName];
-      FProfile.addTotalSamples(NumSamples);
-      FProfile.addHeadSamples(NumHeadSamples);
+      MergeResult(Result, FProfile.addTotalSamples(NumSamples));
+      MergeResult(Result, FProfile.addHeadSamples(NumHeadSamples));
       InlineStack.clear();
       InlineStack.push_back(&FProfile);
     } else {
-      unsigned NumSamples;
+      uint64_t NumSamples;
       StringRef FName;
-      DenseMap<StringRef, unsigned> TargetCountMap;
+      DenseMap<StringRef, uint64_t> TargetCountMap;
       bool IsCallsite;
-      unsigned Depth, LineOffset, Discriminator;
+      uint32_t Depth, LineOffset, Discriminator;
       if (!ParseLine(*LineIt, IsCallsite, Depth, NumSamples, LineOffset,
                      Discriminator, FName, TargetCountMap)) {
         reportError(LineIt.line_number(),
@@ -228,7 +203,7 @@ std::error_code SampleProfileReaderText::read() {
         }
         FunctionSamples &FSamples = InlineStack.back()->functionSamplesAt(
             CallsiteLocation(LineOffset, Discriminator, FName));
-        FSamples.addTotalSamples(NumSamples);
+        MergeResult(Result, FSamples.addTotalSamples(NumSamples));
         InlineStack.push_back(&FSamples);
       } else {
         while (InlineStack.size() > Depth) {
@@ -236,15 +211,33 @@ std::error_code SampleProfileReaderText::read() {
         }
         FunctionSamples &FProfile = *InlineStack.back();
         for (const auto &name_count : TargetCountMap) {
-          FProfile.addCalledTargetSamples(LineOffset, Discriminator,
-                                          name_count.first, name_count.second);
+          MergeResult(Result, FProfile.addCalledTargetSamples(
+                                  LineOffset, Discriminator, name_count.first,
+                                  name_count.second));
         }
-        FProfile.addBodySamples(LineOffset, Discriminator, NumSamples);
+        MergeResult(Result, FProfile.addBodySamples(LineOffset, Discriminator,
+                                                    NumSamples));
       }
     }
   }
 
-  return sampleprof_error::success;
+  return Result;
+}
+
+bool SampleProfileReaderText::hasFormat(const MemoryBuffer &Buffer) {
+  bool result = false;
+
+  // Check that the first non-comment line is a valid function header.
+  line_iterator LineIt(Buffer, /*SkipBlanks=*/true, '#');
+  if (!LineIt.is_at_eof()) {
+    if ((*LineIt)[0] != ' ') {
+      uint64_t NumSamples, NumHeadSamples;
+      StringRef FName;
+      result = ParseHead(*LineIt, FName, NumSamples, NumHeadSamples);
+    }
+  }
+
+  return result;
 }
 
 template <typename T> ErrorOr<T> SampleProfileReaderBinary::readNumber() {
@@ -283,7 +276,7 @@ ErrorOr<StringRef> SampleProfileReaderBinary::readString() {
 
 ErrorOr<StringRef> SampleProfileReaderBinary::readStringFromTable() {
   std::error_code EC;
-  auto Idx = readNumber<unsigned>();
+  auto Idx = readNumber<uint32_t>();
   if (std::error_code EC = Idx.getError())
     return EC;
   if (*Idx >= NameTable.size())
@@ -293,26 +286,25 @@ ErrorOr<StringRef> SampleProfileReaderBinary::readStringFromTable() {
 
 std::error_code
 SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
-  auto Val = readNumber<unsigned>();
-  if (std::error_code EC = Val.getError())
-    return EC;
-  FProfile.addTotalSamples(*Val);
-
-  Val = readNumber<unsigned>();
-  if (std::error_code EC = Val.getError())
+  auto NumSamples = readNumber<uint64_t>();
+  if (std::error_code EC = NumSamples.getError())
     return EC;
-  FProfile.addHeadSamples(*Val);
+  FProfile.addTotalSamples(*NumSamples);
 
   // Read the samples in the body.
-  auto NumRecords = readNumber<unsigned>();
+  auto NumRecords = readNumber<uint32_t>();
   if (std::error_code EC = NumRecords.getError())
     return EC;
 
-  for (unsigned I = 0; I < *NumRecords; ++I) {
+  for (uint32_t I = 0; I < *NumRecords; ++I) {
     auto LineOffset = readNumber<uint64_t>();
     if (std::error_code EC = LineOffset.getError())
       return EC;
 
+    if (!isOffsetLegal(*LineOffset)) {
+      return std::error_code();
+    }
+
     auto Discriminator = readNumber<uint64_t>();
     if (std::error_code EC = Discriminator.getError())
       return EC;
@@ -321,11 +313,11 @@ SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
     if (std::error_code EC = NumSamples.getError())
       return EC;
 
-    auto NumCalls = readNumber<unsigned>();
+    auto NumCalls = readNumber<uint32_t>();
     if (std::error_code EC = NumCalls.getError())
       return EC;
 
-    for (unsigned J = 0; J < *NumCalls; ++J) {
+    for (uint32_t J = 0; J < *NumCalls; ++J) {
       auto CalledFunction(readStringFromTable());
       if (std::error_code EC = CalledFunction.getError())
         return EC;
@@ -342,11 +334,11 @@ SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
   }
 
   // Read all the samples for inlined function calls.
-  auto NumCallsites = readNumber<unsigned>();
+  auto NumCallsites = readNumber<uint32_t>();
   if (std::error_code EC = NumCallsites.getError())
     return EC;
 
-  for (unsigned J = 0; J < *NumCallsites; ++J) {
+  for (uint32_t J = 0; J < *NumCallsites; ++J) {
     auto LineOffset = readNumber<uint64_t>();
     if (std::error_code EC = LineOffset.getError())
       return EC;
@@ -370,6 +362,10 @@ SampleProfileReaderBinary::readProfile(FunctionSamples &FProfile) {
 
 std::error_code SampleProfileReaderBinary::read() {
   while (!at_eof()) {
+    auto NumHeadSamples = readNumber<uint64_t>();
+    if (std::error_code EC = NumHeadSamples.getError())
+      return EC;
+
     auto FName(readStringFromTable());
     if (std::error_code EC = FName.getError())
       return EC;
@@ -377,6 +373,8 @@ std::error_code SampleProfileReaderBinary::read() {
     Profiles[*FName] = FunctionSamples();
     FunctionSamples &FProfile = Profiles[*FName];
 
+    FProfile.addHeadSamples(*NumHeadSamples);
+
     if (std::error_code EC = readProfile(FProfile))
       return EC;
   }
@@ -403,11 +401,11 @@ std::error_code SampleProfileReaderBinary::readHeader() {
     return sampleprof_error::unsupported_version;
 
   // Read the name table.
-  auto Size = readNumber<size_t>();
+  auto Size = readNumber<uint32_t>();
   if (std::error_code EC = Size.getError())
     return EC;
   NameTable.reserve(*Size);
-  for (size_t I = 0; I < *Size; ++I) {
+  for (uint32_t I = 0; I < *Size; ++I) {
     auto Name(readString());
     if (std::error_code EC = Name.getError())
       return EC;
@@ -678,7 +676,7 @@ setupMemoryBuffer(std::string Filename) {
   auto Buffer = std::move(BufferOrErr.get());
 
   // Sanity check the file.
-  if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
+  if (Buffer->getBufferSize() > std::numeric_limits<uint32_t>::max())
     return sampleprof_error::too_large;
 
   return std::move(Buffer);
@@ -698,15 +696,29 @@ SampleProfileReader::create(StringRef Filename, LLVMContext &C) {
   auto BufferOrError = setupMemoryBuffer(Filename);
   if (std::error_code EC = BufferOrError.getError())
     return EC;
+  return create(BufferOrError.get(), C);
+}
 
-  auto Buffer = std::move(BufferOrError.get());
+/// \brief Create a sample profile reader based on the format of the input data.
+///
+/// \param B The memory buffer to create the reader from (assumes ownership).
+///
+/// \param Reader The reader to instantiate according to \p Filename's format.
+///
+/// \param C The LLVM context to use to emit diagnostics.
+///
+/// \returns an error code indicating the status of the created reader.
+ErrorOr<std::unique_ptr<SampleProfileReader>>
+SampleProfileReader::create(std::unique_ptr<MemoryBuffer> &B, LLVMContext &C) {
   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));
+  if (SampleProfileReaderBinary::hasFormat(*B))
+    Reader.reset(new SampleProfileReaderBinary(std::move(B), C));
+  else if (SampleProfileReaderGCC::hasFormat(*B))
+    Reader.reset(new SampleProfileReaderGCC(std::move(B), C));
+  else if (SampleProfileReaderText::hasFormat(*B))
+    Reader.reset(new SampleProfileReaderText(std::move(B), C));
   else
-    Reader.reset(new SampleProfileReaderText(std::move(Buffer), C));
+    return sampleprof_error::unrecognized_format;
 
   if (std::error_code EC = Reader->readHeader())
     return EC;