llvm-mirror/lib/ProfileData/InstrProfWriter.cpp
Justin Bogner 48a07cae49 InstrProf: Allow multiple functions with the same name
This updates the instrumentation based profiling format so that when
we have multiple functions with the same name (but different function
hashes) we keep all of them instead of rejecting the later ones.

There are a number of scenarios where this can come up where it's more
useful to keep multiple function profiles:

* Name collisions in unrelated libraries that are profiled together.
* Multiple "main" functions from multiple tools built against a common
  library.
* Combining profiles from different build configurations (ie, asserts
  and no-asserts)

The profile format now stores the number of counters between the hash
and the counts themselves, so that multiple sets of counts can be
stored. Since this is backwards incompatible, I've bumped the format
version and added some trivial logic to skip this when reading the old
format.

llvm-svn: 214585
2014-08-01 22:50:07 +00:00

137 lines
4.2 KiB
C++

//=-- InstrProfWriter.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/ProfileData/InstrProfWriter.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/OnDiskHashTable.h"
#include "InstrProfIndexed.h"
using namespace llvm;
namespace {
class InstrProfRecordTrait {
public:
typedef StringRef key_type;
typedef StringRef key_type_ref;
typedef const InstrProfWriter::CounterData *const data_type;
typedef const InstrProfWriter::CounterData *const data_type_ref;
typedef uint64_t hash_value_type;
typedef uint64_t offset_type;
static hash_value_type ComputeHash(key_type_ref K) {
return IndexedInstrProf::ComputeHash(IndexedInstrProf::HashType, K);
}
static std::pair<offset_type, offset_type>
EmitKeyDataLength(raw_ostream &Out, key_type_ref K, data_type_ref V) {
using namespace llvm::support;
endian::Writer<little> LE(Out);
offset_type N = K.size();
LE.write<offset_type>(N);
offset_type M = 0;
for (const auto &Counts : *V)
M += (2 + Counts.second.size()) * sizeof(uint64_t);
LE.write<offset_type>(M);
return std::make_pair(N, M);
}
static void EmitKey(raw_ostream &Out, key_type_ref K, offset_type N){
Out.write(K.data(), N);
}
static void EmitData(raw_ostream &Out, key_type_ref, data_type_ref V,
offset_type) {
using namespace llvm::support;
endian::Writer<little> LE(Out);
for (const auto &Counts : *V) {
LE.write<uint64_t>(Counts.first);
LE.write<uint64_t>(Counts.second.size());
for (uint64_t I : Counts.second)
LE.write<uint64_t>(I);
}
}
};
}
std::error_code
InstrProfWriter::addFunctionCounts(StringRef FunctionName,
uint64_t FunctionHash,
ArrayRef<uint64_t> Counters) {
auto &CounterData = FunctionData[FunctionName];
auto Where = CounterData.find(FunctionHash);
if (Where == CounterData.end()) {
// We've never seen a function with this name and hash, add it.
CounterData[FunctionHash] = Counters;
// We keep track of the max function count as we go for simplicity.
if (Counters[0] > MaxFunctionCount)
MaxFunctionCount = Counters[0];
return instrprof_error::success;
}
// We're updating a function we've seen before.
auto &FoundCounters = Where->second;
// If the number of counters doesn't match we either have bad data or a hash
// collision.
if (FoundCounters.size() != Counters.size())
return instrprof_error::count_mismatch;
for (size_t I = 0, E = Counters.size(); I < E; ++I) {
if (FoundCounters[I] + Counters[I] < FoundCounters[I])
return instrprof_error::counter_overflow;
FoundCounters[I] += Counters[I];
}
// We keep track of the max function count as we go for simplicity.
if (FoundCounters[0] > MaxFunctionCount)
MaxFunctionCount = FoundCounters[0];
return instrprof_error::success;
}
void InstrProfWriter::write(raw_fd_ostream &OS) {
OnDiskChainedHashTableGenerator<InstrProfRecordTrait> Generator;
// Populate the hash table generator.
std::vector<uint64_t> CounterBuffer;
for (const auto &I : FunctionData)
Generator.insert(I.getKey(), &I.getValue());
using namespace llvm::support;
endian::Writer<little> LE(OS);
// Write the header.
LE.write<uint64_t>(IndexedInstrProf::Magic);
LE.write<uint64_t>(IndexedInstrProf::Version);
LE.write<uint64_t>(MaxFunctionCount);
LE.write<uint64_t>(static_cast<uint64_t>(IndexedInstrProf::HashType));
// Save a space to write the hash table start location.
uint64_t HashTableStartLoc = OS.tell();
LE.write<uint64_t>(0);
// Write the hash table.
uint64_t HashTableStart = Generator.Emit(OS);
// Go back and fill in the hash table start.
OS.seek(HashTableStartLoc);
LE.write<uint64_t>(HashTableStart);
}