mirror of
https://github.com/llvm/llvm-project.git
synced 2025-05-07 23:56:06 +00:00

This patch adds support for reading sample profiles with inline stacks. Inline stacks in a profile are generated when the sampled binary has samples in inlined functions. For instance, if main() calls foo() and foo() calls bar(), and bar() is inlined into foo() and foo() inlined into main(), the profile may look something like: main total:364084 head:0 [ ... ] 2.3: _Z3fool total:243786 1: 60149 1.2: 38568 1.4: 46511 1.7: _Z3bari total:98558 1.1: 52672 1.2: 45886 At line 2, discriminator 3, main() calls foo(). In turn, foo() calls bar() at line 1, discriminator 7. In the textual format, this stacking of inline calls is represented with indentation. With this change, LLVM can now read sample profile files generated by the create_gcov tool from https://github.com/google/autofdo. llvm-svn: 249644
140 lines
4.3 KiB
C++
140 lines
4.3 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.
|
|
bool 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 << ": ";
|
|
write(Loc.CalleeName, CalleeSamples);
|
|
}
|
|
Indent -= 1;
|
|
|
|
return true;
|
|
}
|
|
|
|
SampleProfileWriterBinary::SampleProfileWriterBinary(StringRef F,
|
|
std::error_code &EC)
|
|
: SampleProfileWriter(F, EC, sys::fs::F_None) {
|
|
if (EC)
|
|
return;
|
|
|
|
// Write the file header.
|
|
encodeULEB128(SPMagic(), OS);
|
|
encodeULEB128(SPVersion(), OS);
|
|
}
|
|
|
|
/// \brief Write samples to a binary file.
|
|
///
|
|
/// \returns true if the samples were written successfully, false otherwise.
|
|
bool SampleProfileWriterBinary::write(StringRef FName,
|
|
const FunctionSamples &S) {
|
|
if (S.empty())
|
|
return true;
|
|
|
|
OS << FName;
|
|
encodeULEB128(0, OS);
|
|
encodeULEB128(S.getTotalSamples(), OS);
|
|
encodeULEB128(S.getHeadSamples(), OS);
|
|
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()) {
|
|
std::string Callee = J.first();
|
|
unsigned CalleeSamples = J.second;
|
|
OS << Callee;
|
|
encodeULEB128(0, OS);
|
|
encodeULEB128(CalleeSamples, OS);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// \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
|
|
EC = sampleprof_error::unrecognized_format;
|
|
|
|
if (EC)
|
|
return EC;
|
|
|
|
return std::move(Writer);
|
|
}
|