mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-24 04:09:47 +00:00
Back out Profile library and dependent commits
Chandler voiced some concern with checking this in without some discussion first. Reverting for now. This reverts r203703, r203704, r203708, and 203709. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@203723 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
4a0593ccd3
commit
efa9416a21
@ -1,56 +0,0 @@
|
||||
//=-- ProfileData.h - Instrumented profiling format support -------*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for instrumentation based PGO and coverage.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_PROFILE_PROFILEDATA_H__
|
||||
#define LLVM_PROFILE_PROFILEDATA_H__
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/system_error.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
const char PROFILEDATA_MAGIC[4] = {'L', 'P', 'R', 'F'};
|
||||
const uint32_t PROFILEDATA_VERSION = 1;
|
||||
const uint32_t PROFILEDATA_HEADER_SIZE = 24;
|
||||
|
||||
const error_category &profiledata_category();
|
||||
|
||||
struct profiledata_error {
|
||||
enum ErrorType {
|
||||
success = 0,
|
||||
bad_magic,
|
||||
unsupported_version,
|
||||
too_large,
|
||||
truncated,
|
||||
malformed,
|
||||
unknown_function
|
||||
};
|
||||
ErrorType V;
|
||||
|
||||
profiledata_error(ErrorType V) : V(V) {}
|
||||
operator ErrorType() const { return V; }
|
||||
};
|
||||
|
||||
inline error_code make_error_code(profiledata_error E) {
|
||||
return error_code(static_cast<int>(E), profiledata_category());
|
||||
}
|
||||
|
||||
template <> struct is_error_code_enum<profiledata_error> : std::true_type {};
|
||||
template <> struct is_error_code_enum<profiledata_error::ErrorType>
|
||||
: std::true_type {};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_PROFILE_PROFILEDATA_H__
|
@ -1,91 +0,0 @@
|
||||
//=-- ProfileDataReader.h - Instrumented profiling reader ---------*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for reading profiling data for instrumentation
|
||||
// based PGO and coverage.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_PROFILE_PROFILEDATA_READER_H__
|
||||
#define LLVM_PROFILE_PROFILEDATA_READER_H__
|
||||
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class ProfileDataCursor;
|
||||
|
||||
/// Reader for the profile data that is used for instrumentation based PGO.
|
||||
class ProfileDataReader {
|
||||
private:
|
||||
/// The profile data file contents.
|
||||
std::unique_ptr<MemoryBuffer> DataBuffer;
|
||||
/// Offsets into DataBuffer for each function's counters.
|
||||
StringMap<uint32_t> DataOffsets;
|
||||
/// The maximal execution count among all functions.
|
||||
uint64_t MaxFunctionCount;
|
||||
|
||||
ProfileDataReader(const ProfileDataReader &) LLVM_DELETED_FUNCTION;
|
||||
ProfileDataReader &operator=(const ProfileDataReader &) LLVM_DELETED_FUNCTION;
|
||||
protected:
|
||||
ProfileDataReader(std::unique_ptr<MemoryBuffer> &DataBuffer)
|
||||
: DataBuffer(DataBuffer.release()) {}
|
||||
|
||||
/// Populate internal state using the profile data's index
|
||||
error_code readIndex();
|
||||
public:
|
||||
|
||||
class name_iterator {
|
||||
typedef StringMap<unsigned>::const_iterator IterTy;
|
||||
IterTy Ix;
|
||||
public:
|
||||
explicit name_iterator(const IterTy &Ix) : Ix(Ix) {}
|
||||
|
||||
StringRef operator*() const { return Ix->getKey(); }
|
||||
|
||||
bool operator==(const name_iterator &RHS) const { return Ix == RHS.Ix; }
|
||||
bool operator!=(const name_iterator &RHS) const { return Ix != RHS.Ix; }
|
||||
|
||||
inline name_iterator& operator++() { ++Ix; return *this; }
|
||||
};
|
||||
|
||||
/// Iterators over the names of indexed items
|
||||
name_iterator begin() const {
|
||||
return name_iterator(DataOffsets.begin());
|
||||
}
|
||||
name_iterator end() const {
|
||||
return name_iterator(DataOffsets.end());
|
||||
}
|
||||
|
||||
private:
|
||||
error_code findFunctionCounts(StringRef FuncName, uint64_t &FunctionHash,
|
||||
ProfileDataCursor &Cursor);
|
||||
public:
|
||||
/// The number of profiled functions
|
||||
size_t numProfiledFunctions() { return DataOffsets.size(); }
|
||||
/// Fill Counts with the profile data for the given function name.
|
||||
error_code getFunctionCounts(StringRef FuncName, uint64_t &FunctionHash,
|
||||
std::vector<uint64_t> &Counts);
|
||||
/// Return the maximum of all known function counts.
|
||||
uint64_t getMaximumFunctionCount() { return MaxFunctionCount; }
|
||||
|
||||
static error_code create(std::string Path,
|
||||
std::unique_ptr<ProfileDataReader> &Result);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_PROFILE_PROFILEDATA_READER_H__
|
@ -1,47 +0,0 @@
|
||||
//=-- ProfileDataWriter.h - Instrumented profiling writer ---------*- C++ -*-=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for writing profiling data for instrumentation
|
||||
// based PGO and coverage.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_PROFILE_PROFILEDATA_WRITER_H__
|
||||
#define LLVM_PROFILE_PROFILEDATA_WRITER_H__
|
||||
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/Profile/ProfileData.h"
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Writer for instrumentation based profile data
|
||||
class ProfileDataWriter {
|
||||
StringMap<size_t> FunctionOffsets;
|
||||
std::vector<uint64_t> FunctionData;
|
||||
uint32_t DataStart;
|
||||
uint64_t MaxFunctionCount;
|
||||
|
||||
void write32(raw_ostream &OS, uint32_t Value);
|
||||
void write64(raw_ostream &OS, uint64_t Value);
|
||||
public:
|
||||
ProfileDataWriter()
|
||||
: DataStart(PROFILEDATA_HEADER_SIZE), MaxFunctionCount(0) {}
|
||||
|
||||
void addFunctionCounts(StringRef FuncName, uint64_t FunctionHash,
|
||||
uint64_t NumCounters, const uint64_t *Counters);
|
||||
void write(raw_ostream &OS);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_PROFILE_PROFILEDATA_WRITER_H__
|
@ -56,7 +56,6 @@ public:
|
||||
|
||||
/// \brief Get the current line as a \c StringRef.
|
||||
StringRef operator*() const { return CurrentLine; }
|
||||
const StringRef *operator->() const { return &CurrentLine; }
|
||||
|
||||
friend bool operator==(const line_iterator &LHS, const line_iterator &RHS) {
|
||||
return LHS.Buffer == RHS.Buffer &&
|
||||
|
@ -16,4 +16,3 @@ add_subdirectory(ExecutionEngine)
|
||||
add_subdirectory(Target)
|
||||
add_subdirectory(AsmParser)
|
||||
add_subdirectory(LineEditor)
|
||||
add_subdirectory(Profile)
|
||||
|
@ -16,7 +16,7 @@
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[common]
|
||||
subdirectories = Analysis AsmParser Bitcode CodeGen DebugInfo ExecutionEngine LineEditor Linker IR IRReader LTO MC Object Option Profile Support TableGen Target Transforms
|
||||
subdirectories = Analysis AsmParser Bitcode CodeGen DebugInfo ExecutionEngine LineEditor Linker IR IRReader LTO MC Object Option Support TableGen Target Transforms
|
||||
|
||||
[component_0]
|
||||
type = Group
|
||||
|
@ -12,6 +12,6 @@ include $(LEVEL)/Makefile.config
|
||||
|
||||
PARALLEL_DIRS := IR AsmParser Bitcode Analysis Transforms CodeGen Target \
|
||||
ExecutionEngine Linker LTO MC Object Option DebugInfo \
|
||||
IRReader LineEditor Profile
|
||||
IRReader LineEditor
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
||||
|
@ -1,5 +0,0 @@
|
||||
add_llvm_library(LLVMProfile
|
||||
ProfileData.cpp
|
||||
ProfileDataReader.cpp
|
||||
ProfileDataWriter.cpp
|
||||
)
|
@ -1,21 +0,0 @@
|
||||
;===- ./lib/Profile/LLVMBuild.txt ------------------------------*- Conf -*--===;
|
||||
;
|
||||
; The LLVM Compiler Infrastructure
|
||||
;
|
||||
; This file is distributed under the University of Illinois Open Source
|
||||
; License. See LICENSE.TXT for details.
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
name = Profile
|
||||
parent = Libraries
|
@ -1,14 +0,0 @@
|
||||
##===- lib/Profile/Makefile --------------------------------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LEVEL = ../..
|
||||
LIBRARYNAME = LLVMProfile
|
||||
BUILD_ARCHIVE := 1
|
||||
|
||||
include $(LEVEL)/Makefile.common
|
@ -1,54 +0,0 @@
|
||||
//=-- ProfileData.cpp - Instrumented profiling format support ---------------=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for clang's instrumentation based PGO and
|
||||
// coverage.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Profile/ProfileData.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
class ProfileDataErrorCategoryType : public _do_message {
|
||||
const char *name() const override { return "llvm.profiledata"; }
|
||||
std::string message(int IE) const {
|
||||
profiledata_error::ErrorType E =
|
||||
static_cast<profiledata_error::ErrorType>(IE);
|
||||
switch (E) {
|
||||
case profiledata_error::success: return "Success";
|
||||
case profiledata_error::bad_magic:
|
||||
return "Invalid file format (bad magic)";
|
||||
case profiledata_error::unsupported_version:
|
||||
return "Unsupported format version";
|
||||
case profiledata_error::too_large:
|
||||
return "Too much profile data";
|
||||
case profiledata_error::truncated:
|
||||
return "Truncated profile data";
|
||||
case profiledata_error::malformed:
|
||||
return "Malformed profile data";
|
||||
case profiledata_error::unknown_function:
|
||||
return "No profile data available for function";
|
||||
}
|
||||
llvm_unreachable("A value of profiledata_error has no message.");
|
||||
}
|
||||
error_condition default_error_condition(int EV) const {
|
||||
if (EV == profiledata_error::success)
|
||||
return errc::success;
|
||||
return errc::invalid_argument;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const error_category &llvm::profiledata_category() {
|
||||
static ProfileDataErrorCategoryType C;
|
||||
return C;
|
||||
}
|
@ -1,167 +0,0 @@
|
||||
//=-- ProfileDataReader.cpp - Instrumented profiling reader -----------------=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for reading profiling data for clang's
|
||||
// instrumentation based PGO and coverage.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Profile/ProfileDataReader.h"
|
||||
#include "llvm/Profile/ProfileData.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
error_code ProfileDataReader::create(
|
||||
std::string Path, std::unique_ptr<ProfileDataReader> &Result) {
|
||||
std::unique_ptr<MemoryBuffer> Buffer;
|
||||
if (error_code EC = MemoryBuffer::getFileOrSTDIN(Path, Buffer))
|
||||
return EC;
|
||||
|
||||
if (Buffer->getBufferSize() > std::numeric_limits<unsigned>::max())
|
||||
return profiledata_error::too_large;
|
||||
|
||||
Result.reset(new ProfileDataReader(Buffer));
|
||||
if (error_code EC = Result->readIndex())
|
||||
return EC;
|
||||
return profiledata_error::success;
|
||||
}
|
||||
|
||||
class llvm::ProfileDataCursor {
|
||||
const char *Start;
|
||||
const char *Next;
|
||||
const char *End;
|
||||
|
||||
error_code skip(unsigned bytes) {
|
||||
if (Next + bytes > End)
|
||||
return profiledata_error::malformed;
|
||||
Next += bytes;
|
||||
return profiledata_error::success;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
error_code read(T &Result) {
|
||||
typedef support::detail::packed_endian_specific_integral
|
||||
<T, support::little, support::unaligned> Endian_t;
|
||||
const char *Prev = Next;
|
||||
if (error_code EC = skip(sizeof(T)))
|
||||
return EC;
|
||||
Result = *reinterpret_cast<const Endian_t*>(Prev);
|
||||
return profiledata_error::success;
|
||||
}
|
||||
public:
|
||||
ProfileDataCursor(const MemoryBuffer *Buf)
|
||||
: Start(Buf->getBufferStart()), Next(Start), End(Buf->getBufferEnd()) {}
|
||||
bool offsetReached(size_t Offset) { return Start + Offset <= Next; }
|
||||
bool offsetInBounds(size_t Offset) { return Start + Offset < End; }
|
||||
|
||||
error_code skipToOffset(size_t Offset) {
|
||||
if (!offsetInBounds(Offset))
|
||||
return profiledata_error::malformed;
|
||||
Next = Start + Offset;
|
||||
return profiledata_error::success;
|
||||
}
|
||||
|
||||
error_code skip32() { return skip(4); }
|
||||
error_code skip64() { return skip(8); }
|
||||
error_code read32(uint32_t &Result) { return read<uint32_t>(Result); }
|
||||
error_code read64(uint64_t &Result) { return read<uint64_t>(Result); }
|
||||
|
||||
error_code readChars(StringRef &Result, uint32_t Len) {
|
||||
error_code EC;
|
||||
const char *Prev = Next;
|
||||
if (error_code EC = skip(Len))
|
||||
return EC;
|
||||
Result = StringRef(Prev, Len);
|
||||
return profiledata_error::success;
|
||||
}
|
||||
error_code readString(StringRef &Result) {
|
||||
uint32_t Len;
|
||||
if (error_code EC = read32(Len))
|
||||
return EC;
|
||||
return readChars(Result, Len);
|
||||
}
|
||||
};
|
||||
|
||||
error_code ProfileDataReader::readIndex() {
|
||||
ProfileDataCursor Cursor(DataBuffer.get());
|
||||
error_code EC;
|
||||
StringRef Magic;
|
||||
uint32_t Version, IndexEnd, DataStart;
|
||||
|
||||
if ((EC = Cursor.readChars(Magic, 4)))
|
||||
return EC;
|
||||
if (StringRef(PROFILEDATA_MAGIC, 4) != Magic)
|
||||
return profiledata_error::bad_magic;
|
||||
if ((EC = Cursor.read32(Version)))
|
||||
return EC;
|
||||
if (Version != PROFILEDATA_VERSION)
|
||||
return profiledata_error::unsupported_version;
|
||||
if ((EC = Cursor.read32(IndexEnd)))
|
||||
return EC;
|
||||
if ((EC = Cursor.skip32()))
|
||||
return EC;
|
||||
if ((EC = Cursor.read64(MaxFunctionCount)))
|
||||
return EC;
|
||||
|
||||
DataStart = IndexEnd + (sizeof(uint64_t) - IndexEnd % sizeof(uint64_t));
|
||||
while (!Cursor.offsetReached(IndexEnd)) {
|
||||
StringRef FuncName;
|
||||
uint32_t Offset, TotalOffset;
|
||||
if ((EC = Cursor.readString(FuncName)))
|
||||
return EC;
|
||||
if ((EC = Cursor.read32(Offset)))
|
||||
return EC;
|
||||
TotalOffset = DataStart + Offset;
|
||||
if (!Cursor.offsetInBounds(TotalOffset))
|
||||
return profiledata_error::truncated;
|
||||
DataOffsets[FuncName] = TotalOffset;
|
||||
}
|
||||
|
||||
return profiledata_error::success;
|
||||
}
|
||||
|
||||
error_code ProfileDataReader::findFunctionCounts(StringRef FuncName,
|
||||
uint64_t &FunctionHash,
|
||||
ProfileDataCursor &Cursor) {
|
||||
error_code EC;
|
||||
// Find the relevant section of the pgo-data file.
|
||||
const auto &OffsetIter = DataOffsets.find(FuncName);
|
||||
if (OffsetIter == DataOffsets.end())
|
||||
return profiledata_error::unknown_function;
|
||||
// Go there and read the function data
|
||||
if ((EC = Cursor.skipToOffset(OffsetIter->getValue())))
|
||||
return EC;
|
||||
if ((EC = Cursor.read64(FunctionHash)))
|
||||
return EC;
|
||||
return profiledata_error::success;
|
||||
}
|
||||
|
||||
error_code ProfileDataReader::getFunctionCounts(StringRef FuncName,
|
||||
uint64_t &FunctionHash,
|
||||
std::vector<uint64_t> &Counts) {
|
||||
ProfileDataCursor Cursor(DataBuffer.get());
|
||||
error_code EC;
|
||||
if ((EC = findFunctionCounts(FuncName, FunctionHash, Cursor)))
|
||||
return EC;
|
||||
|
||||
uint64_t NumCounters;
|
||||
if ((EC = Cursor.read64(NumCounters)))
|
||||
return EC;
|
||||
for (uint64_t I = 0; I < NumCounters; ++I) {
|
||||
uint64_t Count;
|
||||
if ((EC = Cursor.read64(Count)))
|
||||
return EC;
|
||||
Counts.push_back(Count);
|
||||
}
|
||||
|
||||
return profiledata_error::success;
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
//=-- ProfileDataWriter.cpp - Instrumented profiling writer -----------------=//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains support for writing profiling data for clang's
|
||||
// instrumentation based PGO and coverage.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Profile/ProfileDataWriter.h"
|
||||
#include "llvm/Profile/ProfileData.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
template <typename T>
|
||||
struct LEBytes {
|
||||
const T &Data;
|
||||
LEBytes(const T &Data) : Data(Data) {}
|
||||
void print(raw_ostream &OS) const {
|
||||
for (uint32_t Shift = 0; Shift < sizeof(Data); ++Shift)
|
||||
OS << (char)((Data >> (8 * Shift)) & 0xFF);
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
static raw_ostream &operator<<(raw_ostream &OS, const LEBytes<T> &Bytes) {
|
||||
Bytes.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
void ProfileDataWriter::addFunctionCounts(StringRef FuncName,
|
||||
uint64_t FunctionHash,
|
||||
uint64_t NumCounters,
|
||||
const uint64_t *Counters) {
|
||||
DataStart += 2 * sizeof(uint32_t) + FuncName.size();
|
||||
FunctionOffsets[FuncName] = FunctionData.size() * sizeof(uint64_t);
|
||||
FunctionData.push_back(FunctionHash);
|
||||
FunctionData.push_back(NumCounters);
|
||||
assert(NumCounters > 0 && "Function call counter missing!");
|
||||
if (Counters[0] > MaxFunctionCount)
|
||||
MaxFunctionCount = Counters[0];
|
||||
for (uint64_t I = 0; I < NumCounters; ++I)
|
||||
FunctionData.push_back(Counters[I]);
|
||||
}
|
||||
|
||||
void ProfileDataWriter::write(raw_ostream &OS) {
|
||||
for (char C : PROFILEDATA_MAGIC)
|
||||
OS << C;
|
||||
OS << LEBytes<uint32_t>(PROFILEDATA_VERSION);
|
||||
OS << LEBytes<uint32_t>(DataStart);
|
||||
OS << LEBytes<uint32_t>(0);
|
||||
OS << LEBytes<uint64_t>(MaxFunctionCount);
|
||||
|
||||
for (const auto &I : FunctionOffsets) {
|
||||
StringRef Name = I.getKey();
|
||||
OS << LEBytes<uint32_t>(Name.size());
|
||||
OS << Name;
|
||||
OS << LEBytes<uint32_t>(I.getValue());
|
||||
}
|
||||
|
||||
for (unsigned I = 0; I < sizeof(uint64_t) - DataStart % sizeof(uint64_t); ++I)
|
||||
OS << '\0';
|
||||
|
||||
for (uint64_t Value : FunctionData)
|
||||
OS << LEBytes<uint64_t>(Value);
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
function_count_not 1count
|
||||
1
|
@ -1,4 +0,0 @@
|
||||
function_count_not
|
||||
badhash
|
||||
1
|
||||
1
|
4
test/tools/llvm-profdata/Inputs/bar3-1.profdata
Normal file
4
test/tools/llvm-profdata/Inputs/bar3-1.profdata
Normal file
@ -0,0 +1,4 @@
|
||||
bar 3
|
||||
1
|
||||
2
|
||||
3
|
@ -1,6 +0,0 @@
|
||||
bar
|
||||
3
|
||||
3
|
||||
1
|
||||
2
|
||||
3
|
4
test/tools/llvm-profdata/Inputs/foo3-1.profdata
Normal file
4
test/tools/llvm-profdata/Inputs/foo3-1.profdata
Normal file
@ -0,0 +1,4 @@
|
||||
foo 3
|
||||
1
|
||||
2
|
||||
3
|
@ -1,6 +0,0 @@
|
||||
foo
|
||||
3
|
||||
3
|
||||
1
|
||||
2
|
||||
3
|
4
test/tools/llvm-profdata/Inputs/foo3-2.profdata
Normal file
4
test/tools/llvm-profdata/Inputs/foo3-2.profdata
Normal file
@ -0,0 +1,4 @@
|
||||
foo 3
|
||||
7
|
||||
5
|
||||
3
|
@ -1,6 +0,0 @@
|
||||
foo
|
||||
3
|
||||
3
|
||||
7
|
||||
5
|
||||
3
|
9
test/tools/llvm-profdata/Inputs/foo3bar3-1.profdata
Normal file
9
test/tools/llvm-profdata/Inputs/foo3bar3-1.profdata
Normal file
@ -0,0 +1,9 @@
|
||||
foo 3
|
||||
2
|
||||
3
|
||||
5
|
||||
|
||||
bar 3
|
||||
7
|
||||
11
|
||||
13
|
@ -1,13 +0,0 @@
|
||||
foo
|
||||
3
|
||||
3
|
||||
2
|
||||
3
|
||||
5
|
||||
|
||||
bar
|
||||
3
|
||||
3
|
||||
7
|
||||
11
|
||||
13
|
@ -1,13 +1,9 @@
|
||||
foo
|
||||
3
|
||||
3
|
||||
foo 3
|
||||
17
|
||||
19
|
||||
23
|
||||
|
||||
bar
|
||||
3
|
||||
3
|
||||
bar 3
|
||||
29
|
||||
31
|
||||
37
|
@ -1,6 +1,4 @@
|
||||
foo
|
||||
4
|
||||
4
|
||||
foo 4
|
||||
11
|
||||
22
|
||||
33
|
@ -1,6 +1,4 @@
|
||||
foo
|
||||
4
|
||||
4
|
||||
foo 4
|
||||
7
|
||||
6
|
||||
5
|
@ -0,0 +1,2 @@
|
||||
invalid_count 1
|
||||
1later
|
@ -1,4 +0,0 @@
|
||||
invalid_count
|
||||
1
|
||||
1
|
||||
1later
|
@ -1,4 +1,2 @@
|
||||
overflow
|
||||
1
|
||||
1
|
||||
overflow 1
|
||||
9223372036854775808
|
@ -1,4 +0,0 @@
|
||||
wrong_count
|
||||
3
|
||||
3
|
||||
1
|
22
test/tools/llvm-profdata/errors.test
Normal file
22
test/tools/llvm-profdata/errors.test
Normal file
@ -0,0 +1,22 @@
|
||||
RUN: not llvm-profdata %p/Inputs/empty.profdata %p/Inputs/foo3-1.profdata 2>&1 | FileCheck %s --check-prefix=LENGTH
|
||||
RUN: not llvm-profdata %p/Inputs/foo3-1.profdata %p/Inputs/foo3bar3-1.profdata 2>&1 | FileCheck %s --check-prefix=LENGTH
|
||||
RUN: not llvm-profdata %p/Inputs/foo4-1.profdata %p/Inputs/empty.profdata 2>&1 | FileCheck %s --check-prefix=LENGTH
|
||||
LENGTH: error: {{.*}}: truncated file
|
||||
|
||||
RUN: not llvm-profdata %p/Inputs/foo3-1.profdata %p/Inputs/bar3-1.profdata 2>&1 | FileCheck %s --check-prefix=NAME
|
||||
NAME: error: {{.*}}: function name mismatch
|
||||
|
||||
RUN: not llvm-profdata %p/Inputs/foo3-1.profdata %p/Inputs/foo4-1.profdata 2>&1 | FileCheck %s --check-prefix=COUNT
|
||||
COUNT: error: {{.*}}: function count mismatch
|
||||
|
||||
RUN: not llvm-profdata %p/Inputs/overflow.profdata %p/Inputs/overflow.profdata 2>&1 | FileCheck %s --check-prefix=OVERFLOW
|
||||
OVERFLOW: error: {{.*}}: counter overflow
|
||||
|
||||
RUN: not llvm-profdata %p/Inputs/invalid-count-later.profdata %p/Inputs/invalid-count-later.profdata 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER
|
||||
INVALID-COUNT-LATER: error: {{.*}}: invalid counter
|
||||
|
||||
RUN: not llvm-profdata %p/Inputs/bad-function-count.profdata %p/Inputs/bad-function-count.profdata 2>&1 | FileCheck %s --check-prefix=BAD-FUNCTION-COUNT
|
||||
BAD-FUNCTION-COUNT: error: {{.*}}: bad function count
|
||||
|
||||
RUN: not llvm-profdata %p/Inputs/three-words-long.profdata %p/Inputs/three-words-long.profdata 2>&1 | FileCheck %s --check-prefix=INVALID-DATA
|
||||
INVALID-DATA: error: {{.*}}: invalid data
|
@ -1,38 +0,0 @@
|
||||
RUN: llvm-profdata generate %p/Inputs/empty.profdata.input | llvm-profdata show -all-functions -counts - | FileCheck %s --check-prefix=EMPTY
|
||||
|
||||
EMPTY: Total functions: 0
|
||||
EMPTY: Maximum function count: 0
|
||||
EMPTY: Maximum internal block count: 0
|
||||
|
||||
RUN: llvm-profdata generate %p/Inputs/foo3-1.profdata.input | llvm-profdata show -all-functions -counts - | FileCheck %s --check-prefix=FOO3
|
||||
|
||||
FOO3: foo:
|
||||
FOO3: Counters: 3
|
||||
FOO3: Function count: 1
|
||||
FOO3: Block counts: [2, 3]
|
||||
FOO3: Total functions: 1
|
||||
FOO3: Maximum function count: 1
|
||||
FOO3: Maximum internal block count: 3
|
||||
|
||||
RUN: llvm-profdata generate %p/Inputs/foo3bar3-1.profdata.input | llvm-profdata show -all-functions -counts - | FileCheck %s --check-prefix=FOO3BAR3
|
||||
|
||||
FOO3BAR3: foo:
|
||||
FOO3BAR3: Counters: 3
|
||||
FOO3BAR3: Function count: 2
|
||||
FOO3BAR3: Block counts: [3, 5]
|
||||
FOO3BAR3: bar:
|
||||
FOO3BAR3: Counters: 3
|
||||
FOO3BAR3: Function count: 7
|
||||
FOO3BAR3: Block counts: [11, 13]
|
||||
FOO3BAR3: Total functions: 2
|
||||
FOO3BAR3: Maximum function count: 7
|
||||
FOO3BAR3: Maximum internal block count: 13
|
||||
|
||||
RUN: not llvm-profdata generate %p/Inputs/invalid-count-later.profdata.input -o /dev/null 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER
|
||||
INVALID-COUNT-LATER: error: {{.*}}: Failed to read counter
|
||||
|
||||
RUN: not llvm-profdata generate %p/Inputs/bad-hash.profdata.input -o /dev/null 2>&1 | FileCheck %s --check-prefix=BAD-HASH
|
||||
BAD-HASH: error: {{.*}}: Failed to read hash
|
||||
|
||||
RUN: not llvm-profdata generate %p/Inputs/wrong-count.profdata.input -o /dev/null 2>&1 | FileCheck %s --check-prefix=BAD-FUNCTION-COUNT
|
||||
BAD-FUNCTION-COUNT: error: {{.*}}: Truncated file
|
@ -1,21 +0,0 @@
|
||||
RUN: llvm-profdata generate %p/Inputs/empty.profdata.input > %t-empty.profdata
|
||||
RUN: llvm-profdata generate %p/Inputs/foo3-1.profdata.input > %t-foo3-1.profdata
|
||||
RUN: llvm-profdata generate %p/Inputs/bar3-1.profdata.input > %t-bar3-1.profdata
|
||||
RUN: llvm-profdata generate %p/Inputs/foo3bar3-1.profdata.input > %t-foo3bar3-1.profdata
|
||||
RUN: llvm-profdata generate %p/Inputs/foo4-1.profdata.input > %t-foo4-1.profdata
|
||||
|
||||
RUN: not llvm-profdata merge %t-empty.profdata %t-foo3-1.profdata -o /dev/null 2>&1 | FileCheck %s --check-prefix=LENGTH
|
||||
RUN: not llvm-profdata merge %t-foo3-1.profdata %t-foo3bar3-1.profdata -o /dev/null 2>&1 | FileCheck %s --check-prefix=LENGTH
|
||||
RUN: not llvm-profdata merge %t-foo4-1.profdata %t-empty.profdata -o /dev/null 2>&1 | FileCheck %s --check-prefix=LENGTH
|
||||
LENGTH: error: {{.*}}: Truncated file
|
||||
|
||||
RUN: not llvm-profdata merge %t-foo3-1.profdata %t-bar3-1.profdata -o /dev/null 2>&1 | FileCheck %s --check-prefix=NAME
|
||||
NAME: error: {{.*}}: Function name mismatch
|
||||
|
||||
RUN: not llvm-profdata merge %t-foo3-1.profdata %t-foo4-1.profdata -o /dev/null 2>&1 | FileCheck %s --check-prefix=COUNT
|
||||
COUNT: error: {{.*}}: Function count mismatch
|
||||
|
||||
RUN: llvm-profdata generate %p/Inputs/overflow.profdata.input > %t-overflow.profdata
|
||||
|
||||
RUN: not llvm-profdata merge %t-overflow.profdata %t-overflow.profdata -o /dev/null 2>&1 | FileCheck %s --check-prefix=OVERFLOW
|
||||
OVERFLOW: error: {{.*}}: Counter overflow
|
@ -1,33 +0,0 @@
|
||||
RUN: llvm-profdata generate %p/Inputs/foo3-1.profdata.input > %t-foo3-1.profdata
|
||||
RUN: llvm-profdata generate %p/Inputs/foo3-2.profdata.input > %t-foo3-2.profdata
|
||||
|
||||
RUN: llvm-profdata merge %t-foo3-1.profdata %t-foo3-2.profdata 2>&1 | llvm-profdata show -all-functions -counts - | FileCheck %s --check-prefix=FOO3
|
||||
RUN: llvm-profdata merge %t-foo3-2.profdata %t-foo3-1.profdata 2>&1 | llvm-profdata show -all-functions -counts - | FileCheck %s --check-prefix=FOO3
|
||||
FOO3: foo:
|
||||
FOO3: Counters: 3
|
||||
FOO3: Function count: 8
|
||||
FOO3: Block counts: [7, 6]
|
||||
|
||||
RUN: llvm-profdata generate %p/Inputs/foo4-1.profdata.input > %t-foo4-1.profdata
|
||||
RUN: llvm-profdata generate %p/Inputs/foo4-2.profdata.input > %t-foo4-2.profdata
|
||||
|
||||
RUN: llvm-profdata merge %t-foo4-1.profdata %t-foo4-2.profdata 2>&1 | llvm-profdata show -all-functions -counts - | FileCheck %s --check-prefix=FOO4
|
||||
RUN: llvm-profdata merge %t-foo4-2.profdata %t-foo4-1.profdata 2>&1 | llvm-profdata show -all-functions -counts - | FileCheck %s --check-prefix=FOO4
|
||||
FOO4: foo:
|
||||
FOO4: Counters: 4
|
||||
FOO4: Function count: 18
|
||||
FOO4: Block counts: [28, 38, 48]
|
||||
|
||||
RUN: llvm-profdata generate %p/Inputs/foo3bar3-1.profdata.input > %t-foo3bar3-1.profdata
|
||||
RUN: llvm-profdata generate %p/Inputs/foo3bar3-2.profdata.input > %t-foo3bar3-2.profdata
|
||||
|
||||
RUN: llvm-profdata merge %t-foo3bar3-1.profdata %t-foo3bar3-2.profdata 2>&1 | llvm-profdata show -all-functions -counts - | FileCheck %s --check-prefix=FOO3BAR3
|
||||
RUN: llvm-profdata merge %t-foo3bar3-2.profdata %t-foo3bar3-1.profdata 2>&1 | llvm-profdata show -all-functions -counts - | FileCheck %s --check-prefix=FOO3BAR3
|
||||
FOO3BAR3: foo:
|
||||
FOO3BAR3: Counters: 3
|
||||
FOO3BAR3: Function count: 19
|
||||
FOO3BAR3: Block counts: [22, 28]
|
||||
FOO3BAR3: bar:
|
||||
FOO3BAR3: Counters: 3
|
||||
FOO3BAR3: Function count: 36
|
||||
FOO3BAR3: Block counts: [42, 50]
|
25
test/tools/llvm-profdata/simple.test
Normal file
25
test/tools/llvm-profdata/simple.test
Normal file
@ -0,0 +1,25 @@
|
||||
RUN: llvm-profdata %p/Inputs/foo3-1.profdata %p/Inputs/foo3-2.profdata 2>&1 | FileCheck %s --check-prefix=FOO3
|
||||
RUN: llvm-profdata %p/Inputs/foo3-2.profdata %p/Inputs/foo3-1.profdata 2>&1 | FileCheck %s --check-prefix=FOO3
|
||||
FOO3: {{^foo 3$}}
|
||||
FOO3-NEXT: {{^8$}}
|
||||
FOO3-NEXT: {{^7$}}
|
||||
FOO3-NEXT: {{^6$}}
|
||||
|
||||
RUN: llvm-profdata %p/Inputs/foo4-1.profdata %p/Inputs/foo4-2.profdata 2>&1 | FileCheck %s --check-prefix=FOO4
|
||||
RUN: llvm-profdata %p/Inputs/foo4-2.profdata %p/Inputs/foo4-1.profdata 2>&1 | FileCheck %s --check-prefix=FOO4
|
||||
FOO4: {{^foo 4$}}
|
||||
FOO4-NEXT: {{^18$}}
|
||||
FOO4-NEXT: {{^28$}}
|
||||
FOO4-NEXT: {{^38$}}
|
||||
FOO4-NEXT: {{^48$}}
|
||||
|
||||
RUN: llvm-profdata %p/Inputs/foo3bar3-1.profdata %p/Inputs/foo3bar3-2.profdata 2>&1 | FileCheck %s --check-prefix=FOO3BAR3
|
||||
RUN: llvm-profdata %p/Inputs/foo3bar3-2.profdata %p/Inputs/foo3bar3-1.profdata 2>&1 | FileCheck %s --check-prefix=FOO3BAR3
|
||||
FOO3BAR3: {{^foo 3$}}
|
||||
FOO3BAR3-NEXT: {{^19$}}
|
||||
FOO3BAR3-NEXT: {{^22$}}
|
||||
FOO3BAR3-NEXT: {{^28$}}
|
||||
FOO3BAR3: {{^bar 3$}}
|
||||
FOO3BAR3-NEXT: {{^36$}}
|
||||
FOO3BAR3-NEXT: {{^42$}}
|
||||
FOO3BAR3-NEXT: {{^50$}}
|
@ -1,4 +1,4 @@
|
||||
set(LLVM_LINK_COMPONENTS core profile support)
|
||||
set(LLVM_LINK_COMPONENTS core support )
|
||||
|
||||
add_llvm_tool(llvm-profdata
|
||||
llvm-profdata.cpp
|
||||
|
@ -19,4 +19,4 @@
|
||||
type = Tool
|
||||
name = llvm-profdata
|
||||
parent = Tools
|
||||
required_libraries = Profile Support
|
||||
required_libraries = Support
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
LEVEL := ../..
|
||||
TOOLNAME := llvm-profdata
|
||||
LINK_COMPONENTS := core profile support
|
||||
LINK_COMPONENTS := core support
|
||||
|
||||
# This tool has no plugins, optimize startup time.
|
||||
TOOL_NO_EXPORTS := 1
|
||||
|
@ -12,10 +12,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Profile/ProfileDataReader.h"
|
||||
#include "llvm/Profile/ProfileDataWriter.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/LineIterator.h"
|
||||
#include "llvm/Support/ManagedStatic.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/PrettyStackTrace.h"
|
||||
@ -24,6 +21,67 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static cl::opt<std::string> Filename1(cl::Positional, cl::Required,
|
||||
cl::desc("file1"));
|
||||
static cl::opt<std::string> Filename2(cl::Positional, cl::Required,
|
||||
cl::desc("file2"));
|
||||
|
||||
static cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
|
||||
cl::init("-"),
|
||||
cl::desc("Output file"));
|
||||
static cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
|
||||
cl::aliasopt(OutputFilename));
|
||||
|
||||
static bool readLine(const char *&Start, const char *End, StringRef &S) {
|
||||
if (Start == End)
|
||||
return false;
|
||||
|
||||
for (const char *I = Start; I != End; ++I) {
|
||||
assert(*I && "unexpected binary data");
|
||||
if (*I == '\n') {
|
||||
S = StringRef(Start, I - Start);
|
||||
Start = I + 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
S = StringRef(Start, End - Start);
|
||||
Start = End;
|
||||
return true;
|
||||
}
|
||||
|
||||
static StringRef getWord(const char *&Start, const char *End) {
|
||||
for (const char *I = Start; I != End; ++I)
|
||||
if (*I == ' ') {
|
||||
StringRef S(Start, I - Start);
|
||||
Start = I + 1;
|
||||
return S;
|
||||
}
|
||||
StringRef S(Start, End - Start);
|
||||
Start = End;
|
||||
return S;
|
||||
}
|
||||
|
||||
static size_t splitWords(const StringRef &Line, std::vector<StringRef> &Words) {
|
||||
const char *Start = Line.data();
|
||||
const char *End = Line.data() + Line.size();
|
||||
Words.clear();
|
||||
while (Start != End)
|
||||
Words.push_back(getWord(Start, End));
|
||||
return Words.size();
|
||||
}
|
||||
|
||||
static bool getNumber(const StringRef &S, uint64_t &N) {
|
||||
N = 0;
|
||||
for (StringRef::iterator I = S.begin(), E = S.end(); I != E; ++I)
|
||||
if (*I >= '0' && *I <= '9')
|
||||
N = N * 10 + (*I - '0');
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void exitWithError(const std::string &Message,
|
||||
const std::string &Filename, int64_t Line = -1) {
|
||||
errs() << "error: " << Filename;
|
||||
@ -33,291 +91,87 @@ static void exitWithError(const std::string &Message,
|
||||
::exit(1);
|
||||
}
|
||||
|
||||
int merge_main(int argc, const char *argv[]) {
|
||||
cl::opt<std::string> Filename1(cl::Positional, cl::Required,
|
||||
cl::desc("file1"));
|
||||
cl::opt<std::string> Filename2(cl::Positional, cl::Required,
|
||||
cl::desc("file2"));
|
||||
|
||||
cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
|
||||
cl::init("-"),
|
||||
cl::desc("Output file"));
|
||||
cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
|
||||
cl::aliasopt(OutputFilename));
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
|
||||
|
||||
std::unique_ptr<ProfileDataReader> Reader1, Reader2;
|
||||
if (error_code EC = ProfileDataReader::create(Filename1, Reader1))
|
||||
exitWithError(EC.message(), Filename1);
|
||||
if (error_code EC = ProfileDataReader::create(Filename2, Reader2))
|
||||
exitWithError(EC.message(), Filename2);
|
||||
|
||||
if (OutputFilename.empty())
|
||||
OutputFilename = "-";
|
||||
|
||||
std::string ErrorInfo;
|
||||
raw_fd_ostream Output(OutputFilename.data(), ErrorInfo, sys::fs::F_Text);
|
||||
if (!ErrorInfo.empty())
|
||||
exitWithError(ErrorInfo, OutputFilename);
|
||||
|
||||
if (Output.is_displayed())
|
||||
exitWithError("Refusing to write a binary file to stdout", OutputFilename);
|
||||
|
||||
StringRef Name1, Name2;
|
||||
std::vector<uint64_t> Counts1, Counts2, NewCounts;
|
||||
uint64_t Hash1, Hash2;
|
||||
ProfileDataWriter Writer;
|
||||
ProfileDataReader::name_iterator I1 = Reader1->begin(),
|
||||
E1 = Reader1->end(),
|
||||
I2 = Reader2->begin(),
|
||||
E2 = Reader2->end();
|
||||
for (; I1 != E1 && I2 != E2; ++I1, ++I2) {
|
||||
Name1 = *I1;
|
||||
Name2 = *I2;
|
||||
if (Name1 != Name2)
|
||||
exitWithError("Function name mismatch", Filename2); // ???
|
||||
|
||||
if (error_code EC = Reader1->getFunctionCounts(Name1, Hash1, Counts1))
|
||||
exitWithError(EC.message(), Filename1);
|
||||
if (error_code EC = Reader2->getFunctionCounts(Name2, Hash2, Counts2))
|
||||
exitWithError(EC.message(), Filename2);
|
||||
|
||||
if (Counts1.size() != Counts2.size())
|
||||
exitWithError("Function count mismatch", Filename2); // ???
|
||||
if (Hash1 != Hash2)
|
||||
exitWithError("Function hash mismatch", Filename2); // ???
|
||||
|
||||
for (size_t II = 0, EE = Counts1.size(); II < EE; ++II) {
|
||||
uint64_t Sum = Counts1[II] + Counts2[II];
|
||||
if (Sum < Counts1[II])
|
||||
exitWithError("Counter overflow", Filename2); // ???
|
||||
NewCounts.push_back(Sum);
|
||||
}
|
||||
|
||||
Writer.addFunctionCounts(Name1, Hash1, NewCounts.size(), NewCounts.data());
|
||||
|
||||
Counts1.clear();
|
||||
Counts2.clear();
|
||||
NewCounts.clear();
|
||||
}
|
||||
if (I1 != E1 || I2 != E2)
|
||||
exitWithError("Truncated file", Filename2);
|
||||
|
||||
Writer.write(Output);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct HashPrinter {
|
||||
uint64_t Hash;
|
||||
HashPrinter(uint64_t Hash) : Hash(Hash) {}
|
||||
void print(raw_ostream &OS) const {
|
||||
char Buf[18], *Cur = Buf;
|
||||
*Cur++ = '0'; *Cur++ = 'x';
|
||||
for (unsigned I = 16; I;) {
|
||||
char Digit = 0xF & (Hash >> (--I * 4));
|
||||
*Cur++ = (Digit < 10 ? '0' + Digit : 'A' + Digit - 10);
|
||||
}
|
||||
OS.write(Buf, 18);
|
||||
}
|
||||
};
|
||||
static raw_ostream &operator<<(raw_ostream &OS, const HashPrinter &Hash) {
|
||||
Hash.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
struct FreqPrinter {
|
||||
double Freq;
|
||||
FreqPrinter(double Freq) : Freq(Freq) {}
|
||||
void print(raw_ostream &OS) const {
|
||||
OS << (unsigned)(Freq * 100) << "." << ((unsigned)(Freq * 1000) % 10)
|
||||
<< ((unsigned)(Freq * 10000) % 10) << "%";
|
||||
}
|
||||
};
|
||||
static raw_ostream &operator<<(raw_ostream &OS, const FreqPrinter &Freq) {
|
||||
Freq.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
int show_main(int argc, const char *argv[]) {
|
||||
cl::opt<std::string> Filename(cl::Positional, cl::Required,
|
||||
cl::desc("<profdata-file>"));
|
||||
|
||||
cl::opt<bool> ShowCounts("counts", cl::init(false));
|
||||
cl::opt<bool> ShowAllFunctions("all-functions", cl::init(false));
|
||||
cl::opt<std::string> ShowFunction("function");
|
||||
|
||||
cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
|
||||
cl::init("-"),
|
||||
cl::desc("Output file"));
|
||||
cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
|
||||
cl::aliasopt(OutputFilename));
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data summary\n");
|
||||
|
||||
std::unique_ptr<ProfileDataReader> Reader;
|
||||
if (error_code EC = ProfileDataReader::create(Filename, Reader))
|
||||
exitWithError(EC.message(), Filename);
|
||||
|
||||
if (OutputFilename.empty())
|
||||
OutputFilename = "-";
|
||||
|
||||
std::string ErrorInfo;
|
||||
raw_fd_ostream OS(OutputFilename.data(), ErrorInfo, sys::fs::F_Text);
|
||||
if (!ErrorInfo.empty())
|
||||
exitWithError(ErrorInfo, OutputFilename);
|
||||
|
||||
if (ShowAllFunctions && !ShowFunction.empty())
|
||||
errs() << "warning: -function argument ignored: showing all functions\n";
|
||||
|
||||
uint64_t MaxFunctionCount = Reader->getMaximumFunctionCount();
|
||||
|
||||
uint64_t MaxBlockCount = 0;
|
||||
uint64_t Hash;
|
||||
size_t ShownFunctions = false;
|
||||
std::vector<uint64_t> Counts;
|
||||
for (const auto &Name : *Reader) {
|
||||
bool Show = ShowAllFunctions || Name.find(ShowFunction) != Name.npos;
|
||||
if (error_code EC = Reader->getFunctionCounts(Name, Hash, Counts))
|
||||
exitWithError(EC.message(), Filename);
|
||||
|
||||
if (Show) {
|
||||
double CallFreq = Counts[0] / (double)MaxFunctionCount;
|
||||
|
||||
if (!ShownFunctions)
|
||||
OS << "Counters:\n";
|
||||
++ShownFunctions;
|
||||
|
||||
OS << " " << Name << ":\n"
|
||||
<< " Hash: " << HashPrinter(Hash) << "\n"
|
||||
<< " Relative call frequency: " << FreqPrinter(CallFreq) << "\n"
|
||||
<< " Counters: " << Counts.size() << "\n"
|
||||
<< " Function count: " << Counts[0] << "\n";
|
||||
}
|
||||
|
||||
if (Show && ShowCounts)
|
||||
OS << " Block counts: [";
|
||||
for (size_t I = 1, E = Counts.size(); I < E; ++I) {
|
||||
if (Counts[I] > MaxBlockCount)
|
||||
MaxBlockCount = Counts[I];
|
||||
if (Show && ShowCounts)
|
||||
OS << (I == 1 ? "" : ", ") << Counts[I];
|
||||
}
|
||||
if (Show && ShowCounts)
|
||||
OS << "]\n";
|
||||
|
||||
Counts.clear();
|
||||
}
|
||||
|
||||
if (ShowAllFunctions || !ShowFunction.empty())
|
||||
OS << "Functions shown: " << ShownFunctions << "\n";
|
||||
OS << "Total functions: " << Reader->numProfiledFunctions() << "\n";
|
||||
OS << "Maximum function count: " << MaxFunctionCount << "\n";
|
||||
OS << "Maximum internal block count: " << MaxBlockCount << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
int generate_main(int argc, const char *argv[]) {
|
||||
cl::opt<std::string> InputName(cl::Positional, cl::Required,
|
||||
cl::desc("<input-file>"));
|
||||
|
||||
cl::opt<std::string> OutputFilename("output", cl::value_desc("output"),
|
||||
cl::init("-"),
|
||||
cl::desc("Output file"));
|
||||
cl::alias OutputFilenameA("o", cl::desc("Alias for --output"),
|
||||
cl::aliasopt(OutputFilename));
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data generator\n");
|
||||
|
||||
if (OutputFilename.empty())
|
||||
OutputFilename = "-";
|
||||
|
||||
std::string ErrorInfo;
|
||||
raw_fd_ostream Output(OutputFilename.data(), ErrorInfo, sys::fs::F_Text);
|
||||
if (!ErrorInfo.empty())
|
||||
exitWithError(ErrorInfo, OutputFilename);
|
||||
|
||||
if (Output.is_displayed())
|
||||
exitWithError("Refusing to write a binary file to stdout", OutputFilename);
|
||||
|
||||
std::unique_ptr<MemoryBuffer> Buffer;
|
||||
if (error_code EC = MemoryBuffer::getFile(InputName, Buffer))
|
||||
exitWithError(EC.message(), InputName);
|
||||
|
||||
ProfileDataWriter Writer;
|
||||
StringRef Name;
|
||||
uint64_t Hash, NumCounters;
|
||||
std::vector<uint64_t> Counters;
|
||||
for (line_iterator I(*Buffer, '#'); !I.is_at_end(); ++I) {
|
||||
if (I->empty())
|
||||
continue;
|
||||
Name = *I;
|
||||
if ((++I).is_at_end())
|
||||
exitWithError("Truncated file", InputName, I.line_number());
|
||||
if (I->getAsInteger(10, Hash))
|
||||
exitWithError("Failed to read hash", InputName, I.line_number());
|
||||
if ((++I).is_at_end())
|
||||
exitWithError("Truncated file", InputName, I.line_number());
|
||||
if (I->getAsInteger(10, NumCounters))
|
||||
exitWithError("Failed to read num counters", InputName, I.line_number());
|
||||
for (uint64_t CurCounter = 0; CurCounter < NumCounters; ++CurCounter) {
|
||||
uint64_t Counter;
|
||||
if ((++I).is_at_end())
|
||||
exitWithError("Truncated file", InputName, I.line_number());
|
||||
if (I->getAsInteger(10, Counter))
|
||||
exitWithError("Failed to read counter", InputName, I.line_number());
|
||||
Counters.push_back(Counter);
|
||||
}
|
||||
Writer.addFunctionCounts(Name, Hash, NumCounters, Counters.data());
|
||||
Counters.clear();
|
||||
}
|
||||
|
||||
Writer.write(Output);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
//===----------------------------------------------------------------------===//
|
||||
int main(int argc, char **argv) {
|
||||
// Print a stack trace if we signal out.
|
||||
sys::PrintStackTraceOnErrorSignal();
|
||||
PrettyStackTraceProgram X(argc, argv);
|
||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||
|
||||
StringRef ProgName(sys::path::filename(argv[0]));
|
||||
if (argc > 1) {
|
||||
int (*func)(int, const char *[]) = 0;
|
||||
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
|
||||
|
||||
if (strcmp(argv[1], "merge") == 0)
|
||||
func = merge_main;
|
||||
else if (strcmp(argv[1], "show") == 0)
|
||||
func = show_main;
|
||||
else if (strcmp(argv[1], "generate") == 0)
|
||||
func = generate_main;
|
||||
std::unique_ptr<MemoryBuffer> File1;
|
||||
std::unique_ptr<MemoryBuffer> File2;
|
||||
if (error_code ec = MemoryBuffer::getFile(Filename1, File1))
|
||||
exitWithError(ec.message(), Filename1);
|
||||
if (error_code ec = MemoryBuffer::getFile(Filename2, File2))
|
||||
exitWithError(ec.message(), Filename2);
|
||||
|
||||
if (func) {
|
||||
std::string Invocation(ProgName.str() + " " + argv[1]);
|
||||
argv[1] = Invocation.c_str();
|
||||
return func(argc - 1, argv + 1);
|
||||
if (OutputFilename.empty())
|
||||
OutputFilename = "-";
|
||||
|
||||
std::string ErrorInfo;
|
||||
raw_fd_ostream Output(OutputFilename.data(), ErrorInfo, sys::fs::F_Text);
|
||||
if (!ErrorInfo.empty())
|
||||
exitWithError(ErrorInfo, OutputFilename);
|
||||
|
||||
const char *Start1 = File1->getBufferStart();
|
||||
const char *Start2 = File2->getBufferStart();
|
||||
const char *End1 = File1->getBufferEnd();
|
||||
const char *End2 = File2->getBufferEnd();
|
||||
const char *P1 = Start1;
|
||||
const char *P2 = Start2;
|
||||
|
||||
StringRef Line1, Line2;
|
||||
int64_t Num = 0;
|
||||
while (readLine(P1, End1, Line1)) {
|
||||
++Num;
|
||||
if (!readLine(P2, End2, Line2))
|
||||
exitWithError("truncated file", Filename2, Num);
|
||||
|
||||
std::vector<StringRef> Words1, Words2;
|
||||
if (splitWords(Line1, Words1) != splitWords(Line2, Words2))
|
||||
exitWithError("data mismatch", Filename2, Num);
|
||||
|
||||
if (Words1.size() > 2)
|
||||
exitWithError("invalid data", Filename1, Num);
|
||||
|
||||
if (Words1.empty()) {
|
||||
Output << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[1], "-h") == 0 ||
|
||||
strcmp(argv[1], "-help") == 0 ||
|
||||
strcmp(argv[1], "--help") == 0) {
|
||||
if (Words1.size() == 2) {
|
||||
if (Words1[0] != Words2[0])
|
||||
exitWithError("function name mismatch", Filename2, Num);
|
||||
|
||||
errs() << "OVERVIEW: LLVM profile data tools\n\n"
|
||||
<< "USAGE: " << ProgName << " <command> [args...]\n"
|
||||
<< "USAGE: " << ProgName << " <command> -help\n\n"
|
||||
<< "Available commands: merge, show, generate\n";
|
||||
return 0;
|
||||
uint64_t N1, N2;
|
||||
if (!getNumber(Words1[1], N1))
|
||||
exitWithError("bad function count", Filename1, Num);
|
||||
if (!getNumber(Words2[1], N2))
|
||||
exitWithError("bad function count", Filename2, Num);
|
||||
|
||||
if (N1 != N2)
|
||||
exitWithError("function count mismatch", Filename2, Num);
|
||||
|
||||
Output << Line1 << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t N1, N2;
|
||||
if (!getNumber(Words1[0], N1))
|
||||
exitWithError("invalid counter", Filename1, Num);
|
||||
if (!getNumber(Words2[0], N2))
|
||||
exitWithError("invalid counter", Filename2, Num);
|
||||
|
||||
uint64_t Sum = N1 + N2;
|
||||
if (Sum < N1)
|
||||
exitWithError("counter overflow", Filename2, Num);
|
||||
|
||||
Output << N1 + N2 << "\n";
|
||||
}
|
||||
if (readLine(P2, End2, Line2))
|
||||
exitWithError("truncated file", Filename1, Num + 1);
|
||||
|
||||
if (argc < 2)
|
||||
errs() << ProgName << ": No command specified!\n";
|
||||
else
|
||||
errs() << ProgName << ": Unknown command!\n";
|
||||
|
||||
errs() << "USAGE: " << ProgName << " <merge|show|generate> [args...]\n";
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user