Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 61 additions & 4 deletions src/perf_data_converter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ typedef std::unordered_map<SampleKey, perftools::profiles::Sample*,
//
typedef std::map<uint64_t, uint64_t> LocationMap;

// Map from a function name and source file to a profile function ID.
typedef std::map<std::pair<std::string, std::string>, uint64_t> FunctionMap;

// Map from the handler mapping object to profile mapping ID. The mappings
// the handler creates are immutable and reasonably shared (as in no new mapping
// object is created per, say, each sample), so using the pointers is OK.
Expand Down Expand Up @@ -246,12 +249,23 @@ class PerfDataConverter : public PerfDataHandler {
const PerfDataHandler::Mapping* mapping,
ProfileBuilder* builder);

// Adds a new function to the profile if such function is not present in the
// profile, returning the ID of the function.
uint64_t AddOrGetFunction(const Pid& pid, const std::string& name,
const std::string& source_file,
ProfileBuilder* builder);

// Adds a new mapping to the profile if such mapping is not present in the
// profile, returning the ID of the mapping. It returns 0 to indicate that the
// mapping was not added (only happens if smap == 0 currently).
uint64_t AddOrGetMapping(const Pid& pid, const PerfDataHandler::Mapping* smap,
ProfileBuilder* builder);

// Sets the has_functions flag in the specified mapping.
void SetMappingHasFunctions(const Pid& pid,
const PerfDataHandler::Mapping* smap,
ProfileBuilder* builder);

// Returns whether pid labels were requested for inclusion in the
// profile.proto's Sample.Label field.
bool IncludePidLabels() const { return (sample_labels_ & kPidLabel); }
Expand Down Expand Up @@ -339,13 +353,15 @@ class PerfDataConverter : public PerfDataHandler {
ProfileBuilder* builder = nullptr;
ProcessMeta* process_meta = nullptr;
LocationMap location_map;
FunctionMap function_map;
MappingMap mapping_map;
std::unordered_map<Tid, std::string> tid_to_comm_map;
SampleMap sample_map;
void clear() {
builder = nullptr;
process_meta = nullptr;
location_map.clear();
function_map.clear();
mapping_map.clear();
tid_to_comm_map.clear();
sample_map.clear();
Expand Down Expand Up @@ -569,6 +585,21 @@ ProfileBuilder* PerfDataConverter::GetOrCreateBuilder(
return per_pid.builder;
}

void PerfDataConverter::SetMappingHasFunctions(
const Pid& pid, const PerfDataHandler::Mapping* smap,
ProfileBuilder* builder) {
CHECK(builder != nullptr) << "Cannot modify mapping in null builder";
if (smap == nullptr) return;

MappingMap& mapmap = per_pid_[pid].mapping_map;
auto it = mapmap.find(smap);
CHECK(it != mapmap.end()) << "Mapping not found: " << smap->filename;

Profile* profile = builder->mutable_profile();
uint64_t mapping_id = it->second - 1; // Mapping IDs start at 1.
profile->mutable_mapping(mapping_id)->set_has_functions(true);
}

uint64_t PerfDataConverter::AddOrGetMapping(
const Pid& pid, const PerfDataHandler::Mapping* smap,
ProfileBuilder* builder) {
Expand All @@ -591,11 +622,13 @@ uint64_t PerfDataConverter::AddOrGetMapping(
mapping->set_memory_start(smap->start);
mapping->set_memory_limit(smap->limit);
mapping->set_file_offset(smap->file_offset);
if (!smap->build_id.value.empty()) {
mapping->set_build_id(UTF8StringId(smap->build_id.value, builder));
}
std::string mapping_filename = MappingFilename(smap);
std::string mapping_filename;
if (!smap->build_id.value.empty()) {
mapping->set_build_id(UTF8StringId(smap->build_id.value, builder));
}
mapping_filename = MappingFilename(smap);
mapping->set_filename(UTF8StringId(mapping_filename, builder));
mapping->set_has_filenames(true);
CHECK_LE(mapping->memory_start(), mapping->memory_limit())
<< "Mapping start must be strictly less than its limit: "
<< mapping->filename();
Expand Down Expand Up @@ -746,6 +779,30 @@ void PerfDataConverter::AddOrUpdateSample(
sample->value(2 * event_index + 1) + weight);
}

uint64_t PerfDataConverter::AddOrGetFunction(const Pid& pid,
const std::string& name,
const std::string& source_file,
ProfileBuilder* builder) {
FunctionMap& func_map = per_pid_[pid].function_map;
const auto& key = std::make_pair(name, source_file);
auto func_it = func_map.find(key);
if (func_it != func_map.end()) {
return func_it->second;
}

Profile* profile = builder->mutable_profile();
perftools::profiles::Function* func = profile->add_function();
uint64_t func_id = profile->function_size();
func->set_id(func_id);
func->set_name(UTF8StringId(name, builder));
func->set_system_name(UTF8StringId(name, builder));
func->set_filename(UTF8StringId(source_file, builder));
VLOG(2) << "Added func ID=" << func_id << ", name=" << name
<< ", filename=" << source_file;
func_map[key] = func_id;
return func_id;
}

uint64_t PerfDataConverter::AddOrGetLocation(
const Pid& pid, uint64_t addr, const PerfDataHandler::Mapping* mapping,
ProfileBuilder* builder) {
Expand Down
8 changes: 4 additions & 4 deletions src/profile.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
Expand Down Expand Up @@ -93,11 +93,11 @@ message Profile {
// Index into the string table of the type of the preferred sample
// value. If unset, clients should default to the last sample value.
int64 default_sample_type = 14;
// Documentation link for this profile. The URL must be absolute,
// Documentation link for this profile type. The URL must be absolute,
// e.g., http://pprof.example.com/cpu-profile.html
//
// The URL may be missing if the profile was generated by older code or code
// that did not bother to supply a link.
// The URL may be missing if the profile was generated by code that did not
// supply a link.
int64 doc_url = 15; // Index into string table.
}

Expand Down
8 changes: 6 additions & 2 deletions src/quipper/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,9 @@ cc_library(
name = "address_mapper",
srcs = ["address_mapper.cc"],
hdrs = ["address_mapper.h"],
deps = [":base"],
deps = [
":base",
],
)

cc_library(
Expand Down Expand Up @@ -356,8 +358,8 @@ cc_library(
visibility = ["//visibility:public"],
deps = [
":binary_data_utils",
":compat",
":kernel",
":perf_data_cc_proto",
":base",
],
)
Expand Down Expand Up @@ -724,12 +726,14 @@ cc_test(
"not_run:arm",
],
deps = [
":binary_data_utils",
":compat",
":compat_gunit",
":file_utils",
":kernel",
":perf_buildid",
":perf_data_utils",
":perf_parser",
":perf_protobuf_io",
":perf_reader",
":perf_serializer",
Expand Down
84 changes: 39 additions & 45 deletions src/quipper/address_mapper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

#include "address_mapper.h"

#include <stdint.h>

#include <cstdint>
#include <ios>
#include <iterator>
#include <utility>
#include <vector>

#include "base/logging.h"
Expand All @@ -24,17 +25,18 @@ AddressMapper::AddressMapper(const AddressMapper& other) {
}
}

bool AddressMapper::MapWithID(const uint64_t real_addr, const uint64_t size,
const uint64_t id, const uint64_t offset_base,
bool remove_existing_mappings,
bool allow_unaligned_jit_mappings) {
bool AddressMapper::MapWithIDInternal(uint64_t real_addr, uint64_t size,
uint64_t id, uint64_t offset_base,
bool remove_existing_mappings,
bool allow_unaligned_mappings) {
if (size == 0) {
LOG(ERROR) << "Must allocate a nonzero-length address range.";
return false;
}

if (allow_unaligned_jit_mappings && !remove_existing_mappings) {
LOG(ERROR) << "JIT events have to be able to overwite existing mappings.";
if (allow_unaligned_mappings && !remove_existing_mappings) {
LOG(ERROR)
<< "Unaligned mappings have to be able to overwite existing mappings.";
return false;
}

Expand Down Expand Up @@ -100,7 +102,7 @@ bool AddressMapper::MapWithID(const uint64_t real_addr, const uint64_t size,
// or end, it will require the end of the old mapping range to be moved,
// which is not allowed. Fake JIT events can map non-page-aligned addresses
// for dynamically generated code.
if (!allow_unaligned_jit_mappings && page_alignment_) {
if (!allow_unaligned_mappings && page_alignment_) {
uint64_t page_offset_start = GetAlignedOffset(range.real_addr);
uint64_t page_offset_end = GetAlignedOffset(range.real_addr + range.size);
if ((gap_before && page_offset_start) || (gap_after && page_offset_end)) {
Expand All @@ -111,26 +113,26 @@ bool AddressMapper::MapWithID(const uint64_t real_addr, const uint64_t size,

// Split the existing old range and insert the new range:
if (gap_before) {
if (!MapWithID(old_range.real_addr, gap_before, old_range.id,
old_range.offset_base, false, false)) {
if (!MapWithIDInternal(old_range.real_addr, gap_before, old_range.id,
old_range.offset_base, false, false)) {
LOG(ERROR) << "Could not map old range from " << std::hex
<< old_range.real_addr << " to "
<< old_range.real_addr + gap_before;
return false;
}
}

if (!MapWithID(range.real_addr, range.size, id, offset_base, false,
false)) {
if (!MapWithIDInternal(range.real_addr, range.size, id, offset_base, false,
false)) {
LOG(ERROR) << "Could not map new range at " << std::hex << range.real_addr
<< " to " << range.real_addr + range.size << " over old range";
return false;
}

if (gap_after) {
if (!MapWithID(range.real_addr + range.size, gap_after, old_range.id,
old_range.offset_base + gap_before + range.size, false,
false)) {
if (!MapWithIDInternal(
range.real_addr + range.size, gap_after, old_range.id,
old_range.offset_base + gap_before + range.size, false, false)) {
LOG(ERROR) << "Could not map old range from " << std::hex
<< old_range.real_addr << " to "
<< old_range.real_addr + gap_before;
Expand Down Expand Up @@ -256,39 +258,31 @@ void AddressMapper::DumpToLog() const {
}
}

bool AddressMapper::GetMappedAddressAndListIterator(
const uint64_t real_addr, uint64_t* mapped_addr,
MappingList::const_iterator* iter) const {
CHECK(mapped_addr);
CHECK(iter);
// Looks up |real_addr| and returns the mapped address.
bool AddressMapper::GetMappedAddress(uint64_t real_addr,
uint64_t* mapped_addr) const {
AddressMapper::MappingList::const_iterator iter =
GetRangeContainingAddress(real_addr);
if (iter == mappings_.end()) return false;

*iter = GetRangeContainingAddress(real_addr);
if (*iter == mappings_.end()) return false;
*mapped_addr = (*iter)->mapped_addr + real_addr - (*iter)->real_addr;
*mapped_addr = iter->mapped_addr + real_addr - iter->real_addr;
return true;
}

void AddressMapper::GetMappedIDAndOffset(
const uint64_t real_addr, MappingList::const_iterator real_addr_iter,
uint64_t* id, uint64_t* offset) const {
CHECK(real_addr_iter != mappings_.end());
CHECK(id);
CHECK(offset);

*id = real_addr_iter->id;
*offset = real_addr - real_addr_iter->real_addr + real_addr_iter->offset_base;
}

uint64_t AddressMapper::GetMaxMappedLength() const {
if (IsEmpty()) return 0;

uint64_t min = mappings_.begin()->mapped_addr;

MappingList::const_iterator iter = mappings_.end();
--iter;
uint64_t max = iter->mapped_addr + iter->size;

return max - min;
// Looks up |real_addr| and returns the mapping's ID and offset from the
// start of the mapped space.
bool AddressMapper::GetMappedAddressIDAndOffset(uint64_t real_addr,
uint64_t* mapped_addr,
uint64_t* id,
uint64_t* offset) const {
AddressMapper::MappingList::const_iterator iter =
GetRangeContainingAddress(real_addr);
if (iter == mappings_.end()) return false;

*mapped_addr = real_addr - iter->real_addr + iter->mapped_addr;
*id = iter->id;
*offset = real_addr - iter->real_addr + iter->offset_base;
return true;
}

void AddressMapper::Unmap(MappingList::iterator mapping_iter) {
Expand Down
Loading