}
}
UpdateRecordForEmbeddedElfPath(record);
- thread_tree_.Update(*record);
if (unwind_dwarf_callchain_ && !post_unwind_) {
+ thread_tree_.Update(*record);
if (!UnwindRecord(record)) {
return false;
}
}
if (record->type() == PERF_RECORD_SAMPLE) {
sample_record_count_++;
- auto& r = *static_cast<SampleRecord*>(record);
- CollectHitFileInfo(r);
} else if (record->type() == PERF_RECORD_LOST) {
lost_record_count_ += static_cast<LostRecord*>(record)->lost;
}
bool RecordCommand::DumpAdditionalFeatures(
const std::vector<std::string>& args) {
+ // Read data section of perf.data to collect hit file information.
+ thread_tree_.ClearThreadAndMap();
+ auto callback = [&](const Record* r) {
+ thread_tree_.Update(*r);
+ if (r->type() == PERF_RECORD_SAMPLE) {
+ CollectHitFileInfo(*reinterpret_cast<const SampleRecord*>(r));
+ }
+ };
+ if (!record_file_writer_->ReadDataSection(callback)) {
+ return false;
+ }
+
size_t feature_count = 4;
if (branch_sampling_) {
feature_count++;
}
uint32_t dso_type = dso->type();
uint64_t min_vaddr = dso->MinVirtualAddress();
+
+ // Dumping all symbols in hit files takes too much space, so only dump
+ // needed symbols.
const std::vector<Symbol>& symbols = dso->GetSymbols();
+ std::vector<const Symbol*> dump_symbols;
+ for (const auto& sym : symbols) {
+ if (sym.HasDumpId()) {
+ dump_symbols.push_back(&sym);
+ }
+ }
+ std::sort(dump_symbols.begin(), dump_symbols.end(), Symbol::CompareByAddr);
+
if (!record_file_writer_->WriteFileFeature(dso->Path(), dso_type, min_vaddr,
- symbols)) {
+ dump_symbols)) {
return false;
}
}
thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
const MapEntry* map =
thread_tree_.FindMap(thread, r.ip_data.ip, r.InKernel());
- if (!map->dso->HasDumpId()) {
- map->dso->CreateDumpId();
+ Dso* dso = map->dso;
+ const Symbol* symbol;
+ if (dump_symbols_) {
+ symbol = thread_tree_.FindSymbol(map, r.ip_data.ip, nullptr, &dso);
+ if (!symbol->HasDumpId()) {
+ dso->CreateSymbolDumpId(symbol);
+ }
+ }
+ if (!dso->HasDumpId()) {
+ dso->CreateDumpId();
}
if (r.sample_type & PERF_SAMPLE_CALLCHAIN) {
- size_t ip_nr = r.callchain_data.ip_nr;
- const uint64_t* ips = r.callchain_data.ips;
- for (size_t i = 0; i < ip_nr; ++i) {
- // Even if a sample is in kernel, its callchain can be in user space.
- map = thread_tree_.FindMap(thread, ips[i]);
- if (!map->dso->HasDumpId()) {
- map->dso->CreateDumpId();
+ bool in_kernel = r.InKernel();
+ bool first_ip = true;
+ for (uint64_t i = 0; i < r.callchain_data.ip_nr; ++i) {
+ uint64_t ip = r.callchain_data.ips[i];
+ if (ip >= PERF_CONTEXT_MAX) {
+ switch (ip) {
+ case PERF_CONTEXT_KERNEL:
+ in_kernel = true;
+ break;
+ case PERF_CONTEXT_USER:
+ in_kernel = false;
+ break;
+ default:
+ LOG(DEBUG) << "Unexpected perf_context in callchain: " << std::hex
+ << ip;
+ }
+ } else {
+ if (first_ip) {
+ first_ip = false;
+ // Remove duplication with sample ip.
+ if (ip == r.ip_data.ip) {
+ continue;
+ }
+ }
+ map = thread_tree_.FindMap(thread, ip, in_kernel);
+ dso = map->dso;
+ if (dump_symbols_) {
+ symbol = thread_tree_.FindSymbol(map, ip, nullptr, &dso);
+ if (!symbol->HasDumpId()) {
+ dso->CreateSymbolDumpId(symbol);
+ }
+ }
+ if (!dso->HasDumpId()) {
+ dso->CreateDumpId();
+ }
}
}
}
return id1 < id2;
}
-static bool CompareSymbolByDumpId(const Symbol* s1, const Symbol* s2) {
- uint32_t id1 = UINT_MAX;
- s1->GetDumpId(&id1);
- uint32_t id2 = UINT_MAX;
- s2->GetDumpId(&id2);
- return id1 < id2;
-}
-
bool ReportSampleCommand::PrintFileInfoInProtobuf() {
std::vector<Dso*> dsos = thread_tree_.GetAllDsos();
std::sort(dsos.begin(), dsos.end(), CompareDsoByDumpId);
dump_symbols.push_back(&sym);
}
}
- std::sort(dump_symbols.begin(), dump_symbols.end(), CompareSymbolByDumpId);
+ std::sort(dump_symbols.begin(), dump_symbols.end(),
+ Symbol::CompareByDumpId);
for (const auto& sym : dump_symbols) {
std::string* symbol = file->add_symbol();
}
}
-static bool CompareSymbol(const Symbol& symbol1, const Symbol& symbol2) {
- return symbol1.addr < symbol2.addr;
-}
-
uint32_t Dso::CreateDumpId() {
CHECK(!HasDumpId());
return dump_id_ = g_dump_id_++;
Load();
}
if (!symbols_.empty()) {
- auto it = std::upper_bound(symbols_.begin(), symbols_.end(), Symbol("", vaddr_in_dso, 0), CompareSymbol);
+ auto it = std::upper_bound(symbols_.begin(), symbols_.end(),
+ Symbol("", vaddr_in_dso, 0),
+ Symbol::CompareValueByAddr);
if (it != symbols_.begin()) {
--it;
if (it->addr <= vaddr_in_dso && (it->addr + it->len > vaddr_in_dso)) {
}
}
if (result) {
- std::sort(symbols_.begin(), symbols_.end(), CompareSymbol);
+ std::sort(symbols_.begin(), symbols_.end(), Symbol::CompareValueByAddr);
FixupSymbolLength();
} else {
symbols_.clear();
return true;
}
+ static bool CompareByDumpId(const Symbol* s1, const Symbol* s2) {
+ uint32_t id1 = UINT_MAX;
+ s1->GetDumpId(&id1);
+ uint32_t id2 = UINT_MAX;
+ s2->GetDumpId(&id2);
+ return id1 < id2;
+ }
+
+ static bool CompareByAddr(const Symbol* s1, const Symbol* s2) {
+ return s1->addr < s2->addr;
+ }
+
+ static bool CompareValueByAddr(const Symbol& s1, const Symbol& s2) {
+ return s1.addr < s2.addr;
+ }
+
private:
const char* name_;
mutable const char* demangled_name_;
bool WriteAttrSection(const std::vector<EventAttrWithId>& attr_ids);
bool WriteRecord(const Record& record);
+ bool ReadDataSection(const std::function<void(const Record*)>& callback);
+
bool BeginWriteFeatures(size_t feature_count);
bool WriteBuildIdFeature(const std::vector<BuildIdRecord>& build_id_records);
bool WriteFeatureString(int feature, const std::string& s);
bool WriteFileFeature(const std::string& file_path,
uint32_t file_type,
uint64_t min_vaddr,
- const std::vector<Symbol>& symbols);
+ const std::vector<const Symbol*>& symbols);
bool EndWriteFeatures();
// Normally, Close() should be called after writing. But if something
bool WriteFileHeader();
bool WriteData(const void* buf, size_t len);
bool Write(const void* buf, size_t len);
+ bool Read(void* buf, size_t len);
bool GetFilePos(uint64_t* file_pos);
bool WriteStringWithLength(const std::string& s);
bool WriteFeatureBegin(int feature);
return true;
}
+bool RecordFileWriter::Read(void* buf, size_t len) {
+ if (len != 0u && fread(buf, len, 1, record_fp_) != 1) {
+ PLOG(ERROR) << "failed to read record file '" << filename_ << "'";
+ return false;
+ }
+ return true;
+}
+
+bool RecordFileWriter::ReadDataSection(const std::function<void(const Record*)>& callback) {
+ if (fseek(record_fp_, data_section_offset_, SEEK_SET) == -1) {
+ PLOG(ERROR) << "fseek() failed";
+ return false;
+ }
+ std::vector<char> record_buf(512);
+ uint64_t read_pos = 0;
+ while (read_pos < data_section_size_) {
+ if (!Read(record_buf.data(), Record::header_size())) {
+ return false;
+ }
+ RecordHeader header(record_buf.data());
+ if (record_buf.size() < header.size) {
+ record_buf.resize(header.size);
+ }
+ if (!Read(record_buf.data() + Record::header_size(), header.size - Record::header_size())) {
+ return false;
+ }
+ read_pos += header.size;
+ std::unique_ptr<Record> r = ReadRecordFromBuffer(event_attr_, header.type, record_buf.data());
+ callback(r.get());
+ }
+ return true;
+}
+
bool RecordFileWriter::GetFilePos(uint64_t* file_pos) {
off_t offset = ftello(record_fp_);
if (offset == -1) {
bool RecordFileWriter::WriteFileFeature(const std::string& file_path,
uint32_t file_type,
uint64_t min_vaddr,
- const std::vector<Symbol>& symbols) {
+ const std::vector<const Symbol*>& symbols) {
uint32_t size = file_path.size() + 1 + sizeof(uint32_t) * 2 +
sizeof(uint64_t) + symbols.size() * (sizeof(uint64_t) + sizeof(uint32_t));
for (const auto& symbol : symbols) {
- size += strlen(symbol.Name()) + 1;
+ size += strlen(symbol->Name()) + 1;
}
std::vector<char> buf(sizeof(uint32_t) + size);
char* p = buf.data();
uint32_t symbol_count = static_cast<uint32_t>(symbols.size());
MoveToBinaryFormat(symbol_count, p);
for (const auto& symbol : symbols) {
- MoveToBinaryFormat(symbol.addr, p);
- uint32_t len = symbol.len;
+ MoveToBinaryFormat(symbol->addr, p);
+ uint32_t len = symbol->len;
MoveToBinaryFormat(len, p);
- MoveToBinaryFormat(symbol.Name(), strlen(symbol.Name()) + 1, p);
+ MoveToBinaryFormat(symbol->Name(), strlen(symbol->Name()) + 1, p);
}
CHECK_EQ(buf.size(), static_cast<size_t>(p - buf.data()));