llvm/lib/ProfileData/SampleProfWriter.cpp
Diego Novillo 9dc572f568 Sample profiles - Re-arrange binary format to emit head samples only on top functions.
The number of samples collected at the head of a function only make
sense for top-level functions (i.e., those actually called as opposed to
being inlined inside another).

Head samples essentially count the time spent inside the function's
prologue.  This clearly doesn't make sense for inlined functions, so we
were always emitting 0 in those.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@250539 91177308-0d34-0410-b5e6-96231b3b80d8
2015-10-16 18:54:35 +00:00

201 lines
6.4 KiB
C++

//===- SampleProfWriter.cpp - Write LLVM sample profile data --------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the class that writes LLVM sample profiles. It
// supports two file formats: text and binary. The textual representation
// is useful for debugging and testing purposes. The binary representation
// is more compact, resulting in smaller file sizes. However, they can
// both be used interchangeably.
//
// See lib/ProfileData/SampleProfReader.cpp for documentation on each of the
// supported formats.
//
//===----------------------------------------------------------------------===//
#include "llvm/ProfileData/SampleProfWriter.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/Support/Regex.h"
using namespace llvm::sampleprof;
using namespace llvm;
/// \brief Write samples to a text file.
std::error_code SampleProfileWriterText::write(StringRef FName,
const FunctionSamples &S) {
OS << FName << ":" << S.getTotalSamples();
if (Indent == 0)
OS << ":" << S.getHeadSamples();
OS << "\n";
for (const auto &I : S.getBodySamples()) {
LineLocation Loc = I.first;
const SampleRecord &Sample = I.second;
OS.indent(Indent + 1);
if (Loc.Discriminator == 0)
OS << Loc.LineOffset << ": ";
else
OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
OS << Sample.getSamples();
for (const auto &J : Sample.getCallTargets())
OS << " " << J.first() << ":" << J.second;
OS << "\n";
}
Indent += 1;
for (const auto &I : S.getCallsiteSamples()) {
CallsiteLocation Loc = I.first;
const FunctionSamples &CalleeSamples = I.second;
OS.indent(Indent);
if (Loc.Discriminator == 0)
OS << Loc.LineOffset << ": ";
else
OS << Loc.LineOffset << "." << Loc.Discriminator << ": ";
if (std::error_code EC = write(Loc.CalleeName, CalleeSamples))
return EC;
}
Indent -= 1;
return sampleprof_error::success;
}
std::error_code SampleProfileWriterBinary::writeNameIdx(StringRef FName) {
const auto &ret = NameTable.find(FName);
if (ret == NameTable.end())
return sampleprof_error::truncated_name_table;
encodeULEB128(ret->second, OS);
return sampleprof_error::success;
}
void SampleProfileWriterBinary::addName(StringRef FName) {
auto NextIdx = NameTable.size();
NameTable.insert(std::make_pair(FName, NextIdx));
}
void SampleProfileWriterBinary::addNames(const FunctionSamples &S) {
// Add all the names in indirect call targets.
for (const auto &I : S.getBodySamples()) {
const SampleRecord &Sample = I.second;
for (const auto &J : Sample.getCallTargets())
addName(J.first());
}
// Recursively add all the names for inlined callsites.
for (const auto &J : S.getCallsiteSamples()) {
CallsiteLocation Loc = J.first;
const FunctionSamples &CalleeSamples = J.second;
addName(Loc.CalleeName);
addNames(CalleeSamples);
}
}
std::error_code SampleProfileWriterBinary::writeHeader(
const StringMap<FunctionSamples> &ProfileMap) {
// Write file magic identifier.
encodeULEB128(SPMagic(), OS);
encodeULEB128(SPVersion(), OS);
// Generate the name table for all the functions referenced in the profile.
for (const auto &I : ProfileMap) {
addName(I.first());
addNames(I.second);
}
// Write out the name table.
encodeULEB128(NameTable.size(), OS);
for (auto N : NameTable) {
OS << N.first;
encodeULEB128(0, OS);
}
return sampleprof_error::success;
}
std::error_code SampleProfileWriterBinary::writeBody(StringRef FName,
const FunctionSamples &S) {
if (std::error_code EC = writeNameIdx(FName))
return EC;
encodeULEB128(S.getTotalSamples(), OS);
// Emit all the body samples.
encodeULEB128(S.getBodySamples().size(), OS);
for (const auto &I : S.getBodySamples()) {
LineLocation Loc = I.first;
const SampleRecord &Sample = I.second;
encodeULEB128(Loc.LineOffset, OS);
encodeULEB128(Loc.Discriminator, OS);
encodeULEB128(Sample.getSamples(), OS);
encodeULEB128(Sample.getCallTargets().size(), OS);
for (const auto &J : Sample.getCallTargets()) {
StringRef Callee = J.first();
uint64_t CalleeSamples = J.second;
if (std::error_code EC = writeNameIdx(Callee))
return EC;
encodeULEB128(CalleeSamples, OS);
}
}
// Recursively emit all the callsite samples.
encodeULEB128(S.getCallsiteSamples().size(), OS);
for (const auto &J : S.getCallsiteSamples()) {
CallsiteLocation Loc = J.first;
const FunctionSamples &CalleeSamples = J.second;
encodeULEB128(Loc.LineOffset, OS);
encodeULEB128(Loc.Discriminator, OS);
if (std::error_code EC = writeBody(Loc.CalleeName, CalleeSamples))
return EC;
}
return sampleprof_error::success;
}
/// \brief Write samples of a top-level function to a binary file.
///
/// \returns true if the samples were written successfully, false otherwise.
std::error_code SampleProfileWriterBinary::write(StringRef FName,
const FunctionSamples &S) {
encodeULEB128(S.getHeadSamples(), OS);
return writeBody(FName, S);
}
/// \brief Create a sample profile writer based on the specified format.
///
/// \param Filename The file to create.
///
/// \param Writer The writer to instantiate according to the specified format.
///
/// \param Format Encoding format for the profile file.
///
/// \returns an error code indicating the status of the created writer.
ErrorOr<std::unique_ptr<SampleProfileWriter>>
SampleProfileWriter::create(StringRef Filename, SampleProfileFormat Format) {
std::error_code EC;
std::unique_ptr<SampleProfileWriter> Writer;
if (Format == SPF_Binary)
Writer.reset(new SampleProfileWriterBinary(Filename, EC));
else if (Format == SPF_Text)
Writer.reset(new SampleProfileWriterText(Filename, EC));
else if (Format == SPF_GCC)
EC = sampleprof_error::unsupported_writing_format;
else
EC = sampleprof_error::unrecognized_format;
if (EC)
return EC;
return std::move(Writer);
}