mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 03:33:20 +01:00
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. llvm-svn: 229455
This commit is contained in:
parent
bfe1d906dc
commit
116967eecd
@ -95,6 +95,9 @@ public:
|
|||||||
/// Factory method to create an appropriately typed reader for the given
|
/// Factory method to create an appropriately typed reader for the given
|
||||||
/// instrprof file.
|
/// instrprof file.
|
||||||
static ErrorOr<std::unique_ptr<InstrProfReader>> create(std::string Path);
|
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.
|
/// Reader for the simple text based instrprof format.
|
||||||
@ -294,6 +297,9 @@ public:
|
|||||||
/// Factory method to create an indexed reader.
|
/// Factory method to create an indexed reader.
|
||||||
static ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
|
static ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
|
||||||
create(std::string Path);
|
create(std::string Path);
|
||||||
|
|
||||||
|
static ErrorOr<std::unique_ptr<IndexedInstrProfReader>>
|
||||||
|
create(std::unique_ptr<MemoryBuffer> Buffer);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end namespace llvm
|
} // end namespace llvm
|
||||||
|
@ -41,8 +41,12 @@ public:
|
|||||||
std::error_code addFunctionCounts(StringRef FunctionName,
|
std::error_code addFunctionCounts(StringRef FunctionName,
|
||||||
uint64_t FunctionHash,
|
uint64_t FunctionHash,
|
||||||
ArrayRef<uint64_t> Counters);
|
ArrayRef<uint64_t> Counters);
|
||||||
/// Ensure that all data is written to disk.
|
/// Write the profile to \c OS
|
||||||
void write(raw_fd_ostream &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
|
} // end namespace llvm
|
||||||
|
@ -25,12 +25,7 @@ setupMemoryBuffer(std::string Path) {
|
|||||||
MemoryBuffer::getFileOrSTDIN(Path);
|
MemoryBuffer::getFileOrSTDIN(Path);
|
||||||
if (std::error_code EC = BufferOrErr.getError())
|
if (std::error_code EC = BufferOrErr.getError())
|
||||||
return EC;
|
return EC;
|
||||||
auto Buffer = std::move(BufferOrErr.get());
|
return 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::error_code initializeReader(InstrProfReader &Reader) {
|
static std::error_code initializeReader(InstrProfReader &Reader) {
|
||||||
@ -43,10 +38,16 @@ InstrProfReader::create(std::string Path) {
|
|||||||
auto BufferOrError = setupMemoryBuffer(Path);
|
auto BufferOrError = setupMemoryBuffer(Path);
|
||||||
if (std::error_code EC = BufferOrError.getError())
|
if (std::error_code EC = BufferOrError.getError())
|
||||||
return EC;
|
return EC;
|
||||||
|
return InstrProfReader::create(std::move(BufferOrError.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
auto Buffer = std::move(BufferOrError.get());
|
|
||||||
std::unique_ptr<InstrProfReader> Result;
|
std::unique_ptr<InstrProfReader> Result;
|
||||||
|
|
||||||
// Create the reader.
|
// Create the reader.
|
||||||
if (IndexedInstrProfReader::hasFormat(*Buffer))
|
if (IndexedInstrProfReader::hasFormat(*Buffer))
|
||||||
Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
|
Result.reset(new IndexedInstrProfReader(std::move(Buffer)));
|
||||||
@ -70,14 +71,20 @@ IndexedInstrProfReader::create(std::string Path) {
|
|||||||
auto BufferOrError = setupMemoryBuffer(Path);
|
auto BufferOrError = setupMemoryBuffer(Path);
|
||||||
if (std::error_code EC = BufferOrError.getError())
|
if (std::error_code EC = BufferOrError.getError())
|
||||||
return EC;
|
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.
|
// Create the reader.
|
||||||
if (!IndexedInstrProfReader::hasFormat(*Buffer))
|
if (!IndexedInstrProfReader::hasFormat(*Buffer))
|
||||||
return instrprof_error::bad_magic;
|
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.
|
// Initialize the reader and return the result.
|
||||||
if (std::error_code EC = initializeReader(*Result))
|
if (std::error_code EC = initializeReader(*Result))
|
||||||
|
@ -106,7 +106,7 @@ InstrProfWriter::addFunctionCounts(StringRef FunctionName,
|
|||||||
return instrprof_error::success;
|
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;
|
OnDiskChainedHashTableGenerator<InstrProfRecordTrait> Generator;
|
||||||
|
|
||||||
// Populate the hash table generator.
|
// Populate the hash table generator.
|
||||||
@ -128,7 +128,31 @@ void InstrProfWriter::write(raw_fd_ostream &OS) {
|
|||||||
// Write the hash table.
|
// Write the hash table.
|
||||||
uint64_t HashTableStart = Generator.Emit(OS);
|
uint64_t HashTableStart = Generator.Emit(OS);
|
||||||
|
|
||||||
// Go back and fill in the hash table start.
|
return std::make_pair(HashTableStartLoc, HashTableStart);
|
||||||
OS.seek(HashTableStartLoc);
|
}
|
||||||
LE.write<uint64_t>(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.
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
@ -6,4 +6,5 @@ set(LLVM_LINK_COMPONENTS
|
|||||||
|
|
||||||
add_llvm_unittest(ProfileDataTests
|
add_llvm_unittest(ProfileDataTests
|
||||||
CoverageMappingTest.cpp
|
CoverageMappingTest.cpp
|
||||||
|
InstrProfTest.cpp
|
||||||
)
|
)
|
||||||
|
88
unittests/ProfileData/InstrProfTest.cpp
Normal file
88
unittests/ProfileData/InstrProfTest.cpp
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user