[llvm] r229455 - InstrProf: Add unit tests for the profile reader and writer

Justin Bogner mail at justinbogner.com
Mon Feb 16 15:27:48 PST 2015


Author: bogner
Date: Mon Feb 16 17:27:48 2015
New Revision: 229455

URL: http://llvm.org/viewvc/llvm-project?rev=229455&view=rev
Log:
InstrProf: Add unit tests for the profile reader and writer

This required some minor API to be added to these types to avoid
needing temp files.

Also, I've used initializer lists in the tests, as MSVC 2013 claims to
support them. I'll redo this without them if the bots complain.

Added:
    llvm/trunk/unittests/ProfileData/InstrProfTest.cpp
Modified:
    llvm/trunk/include/llvm/ProfileData/InstrProfReader.h
    llvm/trunk/include/llvm/ProfileData/InstrProfWriter.h
    llvm/trunk/lib/ProfileData/InstrProfReader.cpp
    llvm/trunk/lib/ProfileData/InstrProfWriter.cpp
    llvm/trunk/unittests/ProfileData/CMakeLists.txt

Modified: llvm/trunk/include/llvm/ProfileData/InstrProfReader.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/InstrProfReader.h?rev=229455&r1=229454&r2=229455&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/InstrProfReader.h (original)
+++ llvm/trunk/include/llvm/ProfileData/InstrProfReader.h Mon Feb 16 17:27:48 2015
@@ -95,6 +95,9 @@ public:
   /// Factory method to create an appropriately typed reader for the given
   /// instrprof file.
   static ErrorOr<std::unique_ptr<InstrProfReader>> create(std::string Path);
+
+  static ErrorOr<std::unique_ptr<InstrProfReader>>
+  create(std::unique_ptr<MemoryBuffer> Buffer);
 };
 
 /// Reader for the simple text based instrprof format.
@@ -294,6 +297,9 @@ public:
   /// Factory method to create an indexed reader.
   static ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
   create(std::string Path);
+
+  static ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
+  create(std::unique_ptr<MemoryBuffer> Buffer);
 };
 
 } // end namespace llvm

Modified: llvm/trunk/include/llvm/ProfileData/InstrProfWriter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ProfileData/InstrProfWriter.h?rev=229455&r1=229454&r2=229455&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ProfileData/InstrProfWriter.h (original)
+++ llvm/trunk/include/llvm/ProfileData/InstrProfWriter.h Mon Feb 16 17:27:48 2015
@@ -41,8 +41,12 @@ public:
   std::error_code addFunctionCounts(StringRef FunctionName,
                                     uint64_t FunctionHash,
                                     ArrayRef<uint64_t> Counters);
-  /// Ensure that all data is written to disk.
+  /// Write the profile to \c OS
   void write(raw_fd_ostream &OS);
+  /// Write the profile, returning the raw data. For testing.
+  std::string writeString();
+private:
+  std::pair<uint64_t, uint64_t> writeImpl(raw_ostream &OS);
 };
 
 } // end namespace llvm

Modified: llvm/trunk/lib/ProfileData/InstrProfReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/InstrProfReader.cpp?rev=229455&r1=229454&r2=229455&view=diff
==============================================================================
--- llvm/trunk/lib/ProfileData/InstrProfReader.cpp (original)
+++ llvm/trunk/lib/ProfileData/InstrProfReader.cpp Mon Feb 16 17:27:48 2015
@@ -25,12 +25,7 @@ setupMemoryBuffer(std::string Path) {
       MemoryBuffer::getFileOrSTDIN(Path);
   if (std::error_code EC = BufferOrErr.getError())
     return EC;
-  auto Buffer = std::move(BufferOrErr.get());
-
-  // Sanity check the file.
-  if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
-    return instrprof_error::too_large;
-  return std::move(Buffer);
+  return std::move(BufferOrErr.get());
 }
 
 static std::error_code initializeReader(InstrProfReader &Reader) {
@@ -43,10 +38,16 @@ InstrProfReader::create(std::string Path
   auto BufferOrError = setupMemoryBuffer(Path);
   if (std::error_code EC = BufferOrError.getError())
     return EC;
+  return InstrProfReader::create(std::move(BufferOrError.get()));
+}
 
-  auto Buffer = std::move(BufferOrError.get());
-  std::unique_ptr<InstrProfReader> Result;
+ErrorOr<std::unique_ptr<InstrProfReader>>
+InstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
+  // Sanity check the buffer.
+  if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
+    return instrprof_error::too_large;
 
+  std::unique_ptr<InstrProfReader> Result;
   // Create the reader.
   if (IndexedInstrProfReader::hasFormat(*Buffer))
     Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
@@ -70,14 +71,20 @@ IndexedInstrProfReader::create(std::stri
   auto BufferOrError = setupMemoryBuffer(Path);
   if (std::error_code EC = BufferOrError.getError())
     return EC;
+  return IndexedInstrProfReader::create(std::move(BufferOrError.get()));
+}
+
 
-  auto Buffer = std::move(BufferOrError.get());
-  std::unique_ptr<IndexedInstrProfReader> Result;
+ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
+IndexedInstrProfReader::create(std::unique_ptr<MemoryBuffer> Buffer) {
+  // Sanity check the buffer.
+  if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
+    return instrprof_error::too_large;
 
   // Create the reader.
   if (!IndexedInstrProfReader::hasFormat(*Buffer))
     return instrprof_error::bad_magic;
-  Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
+  auto Result = llvm::make_unique<IndexedInstrProfReader>(std::move(Buffer));
 
   // Initialize the reader and return the result.
   if (std::error_code EC = initializeReader(*Result))

Modified: llvm/trunk/lib/ProfileData/InstrProfWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ProfileData/InstrProfWriter.cpp?rev=229455&r1=229454&r2=229455&view=diff
==============================================================================
--- llvm/trunk/lib/ProfileData/InstrProfWriter.cpp (original)
+++ llvm/trunk/lib/ProfileData/InstrProfWriter.cpp Mon Feb 16 17:27:48 2015
@@ -106,7 +106,7 @@ InstrProfWriter::addFunctionCounts(Strin
   return instrprof_error::success;
 }
 
-void InstrProfWriter::write(raw_fd_ostream &OS) {
+std::pair<uint64_t, uint64_t> InstrProfWriter::writeImpl(raw_ostream &OS) {
   OnDiskChainedHashTableGenerator<InstrProfRecordTrait> Generator;
 
   // Populate the hash table generator.
@@ -128,7 +128,31 @@ void InstrProfWriter::write(raw_fd_ostre
   // Write the hash table.
   uint64_t HashTableStart = Generator.Emit(OS);
 
+  return std::make_pair(HashTableStartLoc, HashTableStart);
+}
+
+void InstrProfWriter::write(raw_fd_ostream &OS) {
+  // Write the hash table.
+  auto TableStart = writeImpl(OS);
+
   // Go back and fill in the hash table start.
-  OS.seek(HashTableStartLoc);
-  LE.write<uint64_t>(HashTableStart);
+  using namespace support;
+  OS.seek(TableStart.first);
+  endian::Writer<little>(OS).write<uint64_t>(TableStart.second);
+}
+
+std::string InstrProfWriter::writeString() {
+  std::string Result;
+  llvm::raw_string_ostream OS(Result);
+  // Write the hash table.
+  auto TableStart = writeImpl(OS);
+  OS.flush();
+
+  // Go back and fill in the hash table start.
+  using namespace support;
+  uint64_t Bytes = endian::byte_swap<uint64_t, little>(TableStart.second);
+  Result.replace(TableStart.first, sizeof(uint64_t), (const char *)&Bytes,
+                 sizeof(uint64_t));
+
+  return Result;
 }

Modified: llvm/trunk/unittests/ProfileData/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ProfileData/CMakeLists.txt?rev=229455&r1=229454&r2=229455&view=diff
==============================================================================
--- llvm/trunk/unittests/ProfileData/CMakeLists.txt (original)
+++ llvm/trunk/unittests/ProfileData/CMakeLists.txt Mon Feb 16 17:27:48 2015
@@ -6,4 +6,5 @@ set(LLVM_LINK_COMPONENTS
 
 add_llvm_unittest(ProfileDataTests
   CoverageMappingTest.cpp
+  InstrProfTest.cpp
   )

Added: llvm/trunk/unittests/ProfileData/InstrProfTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ProfileData/InstrProfTest.cpp?rev=229455&view=auto
==============================================================================
--- llvm/trunk/unittests/ProfileData/InstrProfTest.cpp (added)
+++ llvm/trunk/unittests/ProfileData/InstrProfTest.cpp Mon Feb 16 17:27:48 2015
@@ -0,0 +1,88 @@
+//===- unittest/ProfileData/InstrProfTest.cpp -------------------------------=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ProfileData/InstrProfReader.h"
+#include "llvm/ProfileData/InstrProfWriter.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+
+TEST(InstrProfTest, write_and_read_empty_profile) {
+  InstrProfWriter Writer;
+  std::string Profile = Writer.writeString();
+  auto ReaderOrErr =
+      IndexedInstrProfReader::create(MemoryBuffer::getMemBuffer(Profile));
+  ASSERT_EQ(std::error_code(), ReaderOrErr.getError());
+  auto Reader = std::move(ReaderOrErr.get());
+  ASSERT_TRUE(Reader->begin() == Reader->end());
+}
+
+TEST(InstrProfTest, write_and_read_one_function) {
+  InstrProfWriter Writer;
+  Writer.addFunctionCounts("foo", 0x1234, {1, 2, 3, 4});
+  std::string Profile = Writer.writeString();
+  auto ReaderOrErr =
+      IndexedInstrProfReader::create(MemoryBuffer::getMemBuffer(Profile));
+  ASSERT_EQ(std::error_code(), ReaderOrErr.getError());
+  auto Reader = std::move(ReaderOrErr.get());
+
+  auto I = Reader->begin(), E = Reader->end();
+  ASSERT_TRUE(I != E);
+  ASSERT_EQ(StringRef("foo"), I->Name);
+  ASSERT_EQ(0x1234U, I->Hash);
+  ASSERT_EQ(4U, I->Counts.size());
+  ASSERT_EQ(1U, I->Counts[0]);
+  ASSERT_EQ(2U, I->Counts[1]);
+  ASSERT_EQ(3U, I->Counts[2]);
+  ASSERT_EQ(4U, I->Counts[3]);
+  ASSERT_TRUE(++I == E);
+}
+
+TEST(InstrProfTest, get_function_counts) {
+  InstrProfWriter Writer;
+  Writer.addFunctionCounts("foo", 0x1234, {1, 2});
+  std::string Profile = Writer.writeString();
+  auto ReaderOrErr =
+      IndexedInstrProfReader::create(MemoryBuffer::getMemBuffer(Profile));
+  ASSERT_EQ(std::error_code(), ReaderOrErr.getError());
+  auto Reader = std::move(ReaderOrErr.get());
+
+  std::vector<uint64_t> Counts;
+  std::error_code EC;
+
+  EC = Reader->getFunctionCounts("foo", 0x1234, Counts);
+  ASSERT_EQ(instrprof_error::success, EC);
+  ASSERT_EQ(2U, Counts.size());
+  ASSERT_EQ(1U, Counts[0]);
+  ASSERT_EQ(2U, Counts[1]);
+
+  EC = Reader->getFunctionCounts("foo", 0x5678, Counts);
+  ASSERT_EQ(instrprof_error::hash_mismatch, EC);
+
+  EC = Reader->getFunctionCounts("bar", 0x1234, Counts);
+  ASSERT_EQ(instrprof_error::unknown_function, EC);
+}
+
+TEST(InstrProfTest, get_max_function_count) {
+  InstrProfWriter Writer;
+  Writer.addFunctionCounts("foo", 0x1234, {1ULL << 31, 2});
+  Writer.addFunctionCounts("bar", 0, {1ULL << 63});
+  Writer.addFunctionCounts("baz", 0x5678, {0, 0, 0, 0});
+  std::string Profile = Writer.writeString();
+  auto ReaderOrErr =
+      IndexedInstrProfReader::create(MemoryBuffer::getMemBuffer(Profile));
+  ASSERT_EQ(std::error_code(), ReaderOrErr.getError());
+  auto Reader = std::move(ReaderOrErr.get());
+
+  ASSERT_EQ(1ULL << 63, Reader->getMaximumFunctionCount());
+}
+
+} // end anonymous namespace





More information about the llvm-commits mailing list