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.

llvm-svn: 203723
This commit is contained in:
Justin Bogner 2014-03-12 22:00:57 +00:00
parent d9be72ec44
commit ec49f9820c
42 changed files with 213 additions and 960 deletions

View File

@ -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__

View File

@ -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__

View File

@ -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__

View File

@ -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 &&

View File

@ -16,4 +16,3 @@ add_subdirectory(ExecutionEngine)
add_subdirectory(Target)
add_subdirectory(AsmParser)
add_subdirectory(LineEditor)
add_subdirectory(Profile)

View File

@ -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

View File

@ -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

View File

@ -1,5 +0,0 @@
add_llvm_library(LLVMProfile
ProfileData.cpp
ProfileDataReader.cpp
ProfileDataWriter.cpp
)

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -0,0 +1,2 @@
function_count_not 1count
1

View File

@ -1,4 +0,0 @@
function_count_not
badhash
1
1

View File

@ -0,0 +1,4 @@
bar 3
1
2
3

View File

@ -1,6 +0,0 @@
bar
3
3
1
2
3

View File

@ -0,0 +1,4 @@
foo 3
1
2
3

View File

@ -1,6 +0,0 @@
foo
3
3
1
2
3

View File

@ -0,0 +1,4 @@
foo 3
7
5
3

View File

@ -1,6 +0,0 @@
foo
3
3
7
5
3

View File

@ -0,0 +1,9 @@
foo 3
2
3
5
bar 3
7
11
13

View File

@ -1,13 +0,0 @@
foo
3
3
2
3
5
bar
3
3
7
11
13

View File

@ -0,0 +1,2 @@
invalid_count 1
1later

View File

@ -1,4 +0,0 @@
invalid_count
1
1
1later

View File

@ -1,4 +0,0 @@
wrong_count
3
3
1

View 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

View File

@ -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

View 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

View File

@ -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]

View 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$}}

View File

@ -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

View File

@ -19,4 +19,4 @@
type = Tool
name = llvm-profdata
parent = Tools
required_libraries = Profile Support
required_libraries = Support

View File

@ -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

View File

@ -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;
}