mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-02-20 14:29:27 +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.
|
/// \brief Get the current line as a \c StringRef.
|
||||||
StringRef operator*() const { return CurrentLine; }
|
StringRef operator*() const { return CurrentLine; }
|
||||||
const StringRef *operator->() const { return &CurrentLine; }
|
|
||||||
|
|
||||||
friend bool operator==(const line_iterator &LHS, const line_iterator &RHS) {
|
friend bool operator==(const line_iterator &LHS, const line_iterator &RHS) {
|
||||||
return LHS.Buffer == RHS.Buffer &&
|
return LHS.Buffer == RHS.Buffer &&
|
||||||
|
@ -16,4 +16,3 @@ add_subdirectory(ExecutionEngine)
|
|||||||
add_subdirectory(Target)
|
add_subdirectory(Target)
|
||||||
add_subdirectory(AsmParser)
|
add_subdirectory(AsmParser)
|
||||||
add_subdirectory(LineEditor)
|
add_subdirectory(LineEditor)
|
||||||
add_subdirectory(Profile)
|
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
;===------------------------------------------------------------------------===;
|
;===------------------------------------------------------------------------===;
|
||||||
|
|
||||||
[common]
|
[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]
|
[component_0]
|
||||||
type = Group
|
type = Group
|
||||||
|
@ -12,6 +12,6 @@ include $(LEVEL)/Makefile.config
|
|||||||
|
|
||||||
PARALLEL_DIRS := IR AsmParser Bitcode Analysis Transforms CodeGen Target \
|
PARALLEL_DIRS := IR AsmParser Bitcode Analysis Transforms CodeGen Target \
|
||||||
ExecutionEngine Linker LTO MC Object Option DebugInfo \
|
ExecutionEngine Linker LTO MC Object Option DebugInfo \
|
||||||
IRReader LineEditor Profile
|
IRReader LineEditor
|
||||||
|
|
||||||
include $(LEVEL)/Makefile.common
|
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
|
foo 3
|
||||||
3
|
|
||||||
3
|
|
||||||
17
|
17
|
||||||
19
|
19
|
||||||
23
|
23
|
||||||
|
|
||||||
bar
|
bar 3
|
||||||
3
|
|
||||||
3
|
|
||||||
29
|
29
|
||||||
31
|
31
|
||||||
37
|
37
|
@ -1,6 +1,4 @@
|
|||||||
foo
|
foo 4
|
||||||
4
|
|
||||||
4
|
|
||||||
11
|
11
|
||||||
22
|
22
|
||||||
33
|
33
|
@ -1,6 +1,4 @@
|
|||||||
foo
|
foo 4
|
||||||
4
|
|
||||||
4
|
|
||||||
7
|
7
|
||||||
6
|
6
|
||||||
5
|
5
|
@ -0,0 +1,2 @@
|
|||||||
|
invalid_count 1
|
||||||
|
1later
|
@ -1,4 +0,0 @@
|
|||||||
invalid_count
|
|
||||||
1
|
|
||||||
1
|
|
||||||
1later
|
|
@ -1,4 +1,2 @@
|
|||||||
overflow
|
overflow 1
|
||||||
1
|
|
||||||
1
|
|
||||||
9223372036854775808
|
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
|
add_llvm_tool(llvm-profdata
|
||||||
llvm-profdata.cpp
|
llvm-profdata.cpp
|
||||||
|
@ -19,4 +19,4 @@
|
|||||||
type = Tool
|
type = Tool
|
||||||
name = llvm-profdata
|
name = llvm-profdata
|
||||||
parent = Tools
|
parent = Tools
|
||||||
required_libraries = Profile Support
|
required_libraries = Support
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
LEVEL := ../..
|
LEVEL := ../..
|
||||||
TOOLNAME := llvm-profdata
|
TOOLNAME := llvm-profdata
|
||||||
LINK_COMPONENTS := core profile support
|
LINK_COMPONENTS := core support
|
||||||
|
|
||||||
# This tool has no plugins, optimize startup time.
|
# This tool has no plugins, optimize startup time.
|
||||||
TOOL_NO_EXPORTS := 1
|
TOOL_NO_EXPORTS := 1
|
||||||
|
@ -12,10 +12,7 @@
|
|||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/Profile/ProfileDataReader.h"
|
|
||||||
#include "llvm/Profile/ProfileDataWriter.h"
|
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
#include "llvm/Support/LineIterator.h"
|
|
||||||
#include "llvm/Support/ManagedStatic.h"
|
#include "llvm/Support/ManagedStatic.h"
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
#include "llvm/Support/PrettyStackTrace.h"
|
#include "llvm/Support/PrettyStackTrace.h"
|
||||||
@ -24,6 +21,67 @@
|
|||||||
|
|
||||||
using namespace llvm;
|
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,
|
static void exitWithError(const std::string &Message,
|
||||||
const std::string &Filename, int64_t Line = -1) {
|
const std::string &Filename, int64_t Line = -1) {
|
||||||
errs() << "error: " << Filename;
|
errs() << "error: " << Filename;
|
||||||
@ -33,291 +91,87 @@ static void exitWithError(const std::string &Message,
|
|||||||
::exit(1);
|
::exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int merge_main(int argc, const char *argv[]) {
|
//===----------------------------------------------------------------------===//
|
||||||
cl::opt<std::string> Filename1(cl::Positional, cl::Required,
|
int main(int argc, char **argv) {
|
||||||
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[]) {
|
|
||||||
// Print a stack trace if we signal out.
|
// Print a stack trace if we signal out.
|
||||||
sys::PrintStackTraceOnErrorSignal();
|
sys::PrintStackTraceOnErrorSignal();
|
||||||
PrettyStackTraceProgram X(argc, argv);
|
PrettyStackTraceProgram X(argc, argv);
|
||||||
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
|
||||||
|
|
||||||
StringRef ProgName(sys::path::filename(argv[0]));
|
cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
|
||||||
if (argc > 1) {
|
|
||||||
int (*func)(int, const char *[]) = 0;
|
|
||||||
|
|
||||||
if (strcmp(argv[1], "merge") == 0)
|
std::unique_ptr<MemoryBuffer> File1;
|
||||||
func = merge_main;
|
std::unique_ptr<MemoryBuffer> File2;
|
||||||
else if (strcmp(argv[1], "show") == 0)
|
if (error_code ec = MemoryBuffer::getFile(Filename1, File1))
|
||||||
func = show_main;
|
exitWithError(ec.message(), Filename1);
|
||||||
else if (strcmp(argv[1], "generate") == 0)
|
if (error_code ec = MemoryBuffer::getFile(Filename2, File2))
|
||||||
func = generate_main;
|
exitWithError(ec.message(), Filename2);
|
||||||
|
|
||||||
if (func) {
|
if (OutputFilename.empty())
|
||||||
std::string Invocation(ProgName.str() + " " + argv[1]);
|
OutputFilename = "-";
|
||||||
argv[1] = Invocation.c_str();
|
|
||||||
return func(argc - 1, argv + 1);
|
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 ||
|
if (Words1.size() == 2) {
|
||||||
strcmp(argv[1], "-help") == 0 ||
|
if (Words1[0] != Words2[0])
|
||||||
strcmp(argv[1], "--help") == 0) {
|
exitWithError("function name mismatch", Filename2, Num);
|
||||||
|
|
||||||
errs() << "OVERVIEW: LLVM profile data tools\n\n"
|
uint64_t N1, N2;
|
||||||
<< "USAGE: " << ProgName << " <command> [args...]\n"
|
if (!getNumber(Words1[1], N1))
|
||||||
<< "USAGE: " << ProgName << " <command> -help\n\n"
|
exitWithError("bad function count", Filename1, Num);
|
||||||
<< "Available commands: merge, show, generate\n";
|
if (!getNumber(Words2[1], N2))
|
||||||
return 0;
|
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)
|
return 0;
|
||||||
errs() << ProgName << ": No command specified!\n";
|
|
||||||
else
|
|
||||||
errs() << ProgName << ": Unknown command!\n";
|
|
||||||
|
|
||||||
errs() << "USAGE: " << ProgName << " <merge|show|generate> [args...]\n";
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user