diff --git a/include/virtual_runtime.h b/include/virtual_runtime.h index d94a9a0dab1356f1af6ef08a703a1e3774232fb1..e2fca355139b0317209ff341fc21ba427021c3a5 100644 --- a/include/virtual_runtime.h +++ b/include/virtual_runtime.h @@ -149,6 +149,9 @@ public: bool IsKernelThread(const pid_t pid); void CollectDedupSymbol(kSymbolsHits &kernelSymbolsHits, uSymbolsHits &userSymbolsHits); + void ClearRepeatThreadsMaps(); + void UpdateMapsByRecord(PerfRecordMmap &recordMmap); + void UpdateMapsByRecord(PerfRecordMmap2 &recordMmap2); // debug time #ifdef HIPERF_DEBUG_TIME std::chrono::microseconds updateSymbolsTimes_ = std::chrono::microseconds::zero(); diff --git a/include/virtual_thread.h b/include/virtual_thread.h index 8206a634d40d7c830f0e63180e5fce4be51462b6..ca7e501eb0faf5dac881b6fa0a4ee25517477044 100644 --- a/include/virtual_thread.h +++ b/include/virtual_thread.h @@ -51,6 +51,8 @@ public: memMaps_(processMemMaps_), vaddr4kPageCache_(vaddr4kPageCacheOfProc_), memMapsIndexs_(processMemMapsIndexs_), + isRepeat_(), + hasRepeat_(isRepeat_), parent_(*this) {} VirtualThread(const pid_t pid, const pid_t tid, VirtualThread &thread, @@ -62,6 +64,8 @@ public: memMaps_(thread.processMemMaps_), vaddr4kPageCache_(thread.vaddr4kPageCacheOfProc_), memMapsIndexs_(thread.processMemMapsIndexs_), + isRepeat_(), + hasRepeat_(thread.isRepeat_), parent_(thread) { HLOG_ASSERT(pid != tid); @@ -90,9 +94,18 @@ public: #ifdef HIPERF_DEBUG void ReportVaddrMapMiss(const uint64_t vaddr) const; #endif + bool IsExistRepeatMaps() const + { + return hasRepeat_; + } + void ClearMaps(); private: void SortMemMaps(); + bool IsRepeatMap(int mapIndex, uint64_t begin, uint64_t end) const; + std::vector FindRepeatMapIndexs(uint64_t begin, uint64_t end) const; + void DeleteRepeatMapsByIndex(int index); + void DeleteRepeatMaps(uint64_t begin, uint64_t end, const std::string filename); VirtualThread& GetParent() { return parent_; @@ -112,6 +125,8 @@ private: std::unordered_map &vaddr4kPageCache_; std::vector processMemMapsIndexs_; std::vector &memMapsIndexs_; + bool isRepeat_ = false; + bool &hasRepeat_; VirtualThread &parent_; #ifdef HIPERF_DEBUG mutable std::unordered_set missedRuntimeVaddr_; diff --git a/src/subcommand_record.cpp b/src/subcommand_record.cpp index f2421814141959b488d524be9004be4e6ebb0dd2..9175d87a6dddc720172323f29ce21ded55cac2a9 100644 --- a/src/subcommand_record.cpp +++ b/src/subcommand_record.cpp @@ -1730,6 +1730,7 @@ HiperfError SubCommandRecord::OnSubCommand(std::vector& args) fileWriter_->SetWriteRecordStat(false); } startSaveFileTimes_ = steady_clock::now(); + virtualRuntime_.ClearRepeatThreadsMaps(); if (!backtrack_) { if (!FinishWriteRecordFile()) { HLOGE("Fail to finish record file %s", outputFilename_.c_str()); @@ -2190,6 +2191,16 @@ bool SubCommandRecord::CollectionSymbol(PerfEventRecord& record) virtualRuntime_.SymbolSpeRecord(*sample); } + if (!IsRoot() && record.GetType() == PERF_RECORD_MMAP) { + PerfRecordMmap* recordMmap = static_cast(&record); + virtualRuntime_.UpdateMapsByRecord(*recordMmap); + } + + if (!IsRoot() && record.GetType() == PERF_RECORD_MMAP2) { + PerfRecordMmap2* recordMmap2 = static_cast(&record); + virtualRuntime_.UpdateMapsByRecord(*recordMmap2); + } + return true; } diff --git a/src/utilities.cpp b/src/utilities.cpp index 9de04fff0d58821141a89c37582c9807f967216f..a91451b37bb69a6fd1824c638b4ebbfb61260687 100644 --- a/src/utilities.cpp +++ b/src/utilities.cpp @@ -333,17 +333,21 @@ bool WriteStringToFile(const std::string &fileName, const std::string &value) return output.good(); } -bool IsRoot() +bool GetRootMode() { #if defined(is_ohos) && is_ohos - std::string debugMode = "0"; - debugMode = OHOS::system::GetParameter("const.debuggable", debugMode); - return debugMode == "1"; + return OHOS::system::GetBoolParameter("const.debuggable", false); #else return true; #endif } +bool IsRoot() +{ + const static bool isRoot = GetRootMode(); + return isRoot; +} + bool PowerOfTwo(const uint64_t n) { return n && (!(n & (n - 1))); diff --git a/src/virtual_runtime.cpp b/src/virtual_runtime.cpp index e5e1718cf1cd3a16f2bc61133d84790bf34a07b3..2bc363dfb02cba04a30d8aaea2d60ababf9e0d2f 100644 --- a/src/virtual_runtime.cpp +++ b/src/virtual_runtime.cpp @@ -878,6 +878,47 @@ void VirtualRuntime::UpdateFromRecord(PerfRecordAuxtrace &recordAuxTrace) } } +void VirtualRuntime::UpdateMapsByRecord(PerfRecordMmap &recordMmap) +{ + if (!OHOS::HiviewDFX::DfxMaps::IsLegalMapItem(recordMmap.data_.filename)) { + return; + } + + VirtualThread &thread = GetThread(recordMmap.data_.pid, recordMmap.data_.tid); + if (!thread.IsExistRepeatMaps()) { + return; + } + std::shared_ptr map = thread.CreateMapItem(recordMmap.data_.filename, recordMmap.data_.addr, + recordMmap.data_.len, recordMmap.data_.pgoff); + for (size_t i = 0; i < symbolsFiles_.size(); ++i) { + if (symbolsFiles_[i]->filePath_ == map->name) { + map->symbolFileIndex = static_cast(i); + break; + } + } +} + +void VirtualRuntime::UpdateMapsByRecord(PerfRecordMmap2 &recordMmap2) +{ + if (!OHOS::HiviewDFX::DfxMaps::IsLegalMapItem(recordMmap2.data_.filename)) { + return; + } + + VirtualThread &thread = GetThread(recordMmap2.data_.pid, recordMmap2.data_.tid); + if (!thread.IsExistRepeatMaps()) { + return; + } + std::shared_ptr map = thread.CreateMapItem(recordMmap2.data_.filename, recordMmap2.data_.addr, + recordMmap2.data_.len, + recordMmap2.data_.pgoff, recordMmap2.data_.prot); + for (size_t i = 0; i < symbolsFiles_.size(); ++i) { + if (symbolsFiles_[i]->filePath_ == map->name) { + map->symbolFileIndex = static_cast(i); + break; + } + } +} + void VirtualRuntime::SymbolSpeRecord(PerfRecordAuxtrace &recordAuxTrace) { #if defined(is_ohos) && is_ohos @@ -1144,7 +1185,7 @@ bool VirtualRuntime::GetSymbolCache(const uint64_t fileVaddr, DfxSymbol &symbol, DfxSymbol VirtualRuntime::GetSymbol(const uint64_t ip, const pid_t pid, const pid_t tid, const perf_callchain_context &context) { - HLOGV("try find tid %u ip 0x%" PRIx64 " in %zu symbolsFiles\n", tid, ip, symbolsFiles_.size()); + HLOGV("try find tid %u ip 0x%" PRIx64 " in %zu symbolsFiles", tid, ip, symbolsFiles_.size()); DfxSymbol symbol; if (IsKernelThread(pid)) { @@ -1448,6 +1489,21 @@ void VirtualRuntime::ClearSymbolCache() #endif } +void VirtualRuntime::ClearRepeatThreadsMaps() +{ + // only process repeat maps in user + if (IsRoot()) { + return; + } + HLOGD("ClearRepeatThreadsMaps enter"); + for (auto it = userSpaceThreadMap_.begin(); it != userSpaceThreadMap_.end(); ++it) { + HLOGD("ClearRepeatThreadsMaps pid or tid is %d", it->first); + if (it->second.IsExistRepeatMaps()) { + it->second.ClearMaps(); + } + } +} + } // namespace HiPerf } // namespace Developtools } // namespace OHOS diff --git a/src/virtual_thread.cpp b/src/virtual_thread.cpp index ef65da8822c576d1f00684796de43776d18cea75..aae5a685b13365f077736c17669b57d7733fe0e8 100644 --- a/src/virtual_thread.cpp +++ b/src/virtual_thread.cpp @@ -67,9 +67,9 @@ int64_t VirtualThread::FindMapIndexByAddr(uint64_t addr) const if (memMaps_[memMapsIndexs_[memMapsIndexs_.size() >= 1 ? memMapsIndexs_.size() - 1 : 0]]->end <= addr) { return illegal; } - constexpr int divisorNum {2}; - std::size_t left {0}; - std::size_t right {memMapsIndexs_.size()}; + constexpr int divisorNum = 2; + std::size_t left = 0; + std::size_t right = memMapsIndexs_.size(); std::size_t mid = (right - left) / divisorNum + left; while (left < right) { if (addr < memMaps_[memMapsIndexs_[mid]]->end) { @@ -104,9 +104,9 @@ std::shared_ptr VirtualThread::FindMapByAddr(uint64_t addr) const if (memMaps_[memMapsIndexs_[memMapsIndexs_.size() >= 1 ? memMapsIndexs_.size() - 1 : 0]]->end <= addr) { return nullptr; } - constexpr int divisorNum {2}; - std::size_t left {0}; - std::size_t right {memMapsIndexs_.size()}; + constexpr int divisorNum = 2; + std::size_t left = 0; + std::size_t right = memMapsIndexs_.size(); std::size_t mid = (right - left) / divisorNum + left; while (left < right) { if (addr < memMaps_[memMapsIndexs_[mid]]->end) { @@ -370,6 +370,112 @@ void VirtualThread::ParseDevhostMap(const pid_t devhost) SortMemMaps(); } +bool VirtualThread::IsRepeatMap(int mapIndex, uint64_t begin, uint64_t end) const +{ + return (memMaps_[mapIndex]->begin < end) && (memMaps_[mapIndex]->end > begin); +} + +std::vector VirtualThread::FindRepeatMapIndexs(uint64_t begin, uint64_t end) const +{ + std::vector result = {}; + if (memMaps_.size() == 0) { + return result; + } + if (memMaps_[memMapsIndexs_[0]]->begin >= end) { + return result; + } + if (memMaps_[memMapsIndexs_[memMapsIndexs_.size() >= 1 ? memMapsIndexs_.size() - 1 : 0]]->end <= begin) { + return result; + } + + constexpr int divisorNum {2}; + int left {0}; + int right {memMapsIndexs_.size()}; + int mid = (right - left) / divisorNum + left; + while (left < right) { + if (begin < memMaps_[memMapsIndexs_[mid]]->end) { + right = mid; + mid = (right - left) / divisorNum + left; + continue; + } + if (begin >= memMaps_[memMapsIndexs_[mid]]->end) { + left = mid + 1; + mid = (right - left) / divisorNum + left; + continue; + } + } + right = left + 1; + while (left >= 0) { + if (IsRepeatMap(memMapsIndexs_[left], begin, end)) { + result.push_back(memMapsIndexs_[left]); + } else { + break; + } + left--; + } + while (static_cast(right) < memMaps_.size()) { + if (IsRepeatMap(memMapsIndexs_[right], begin, end)) { + result.push_back(memMapsIndexs_[right]); + } else { + break; + } + right++; + } + + return result; +} + +void VirtualThread::DeleteRepeatMapsByIndex(int index) +{ + auto pos = memMapsIndexs_.begin(); + while (pos != memMapsIndexs_.end()) { + if (index == *pos) { + pos = memMapsIndexs_.erase(pos); + memMaps_.erase(memMaps_.begin() + index); + hasRepeat_ = true; + break; + } + ++pos; + } + auto pos1 = memMapsIndexs_.begin(); + while (pos1 != memMapsIndexs_.end()) { + if (index < *pos1) { + *pos1 -= 1; + } + ++pos1; + } +} + +void VirtualThread::DeleteRepeatMaps(uint64_t begin, uint64_t end, const std::string filename) +{ + auto repeatMaps = FindRepeatMapIndexs(begin, end); + if (repeatMaps.empty()) { + return; + } + + HLOGD("new map: %s, 0x%" PRIx64 "-0x%" PRIx64 "", filename.c_str(), begin, end); + for (auto mapIndex : repeatMaps) { + HLOGD("repeat map: %s", memMaps_[mapIndex]->ToString().c_str()); + } + std::sort(repeatMaps.begin(), repeatMaps.end(), std::greater()); + HLOGD("repeat maps size is %zd", repeatMaps.size()); + for (auto index : repeatMaps) { + DeleteRepeatMapsByIndex(index); + } + vaddr4kPageCache_.clear(); +} + +void VirtualThread::ClearMaps() +{ + HLOGD("clear map"); + if (!memMapsIndexs_.empty()) { + memMapsIndexs_.clear(); + } + if (!memMaps_.empty()) { + memMaps_.clear(); + } +} + void VirtualThread::SortMemMaps() { for (int currPos = 1; currPos < static_cast(memMaps_.size()); ++currPos) { @@ -394,6 +500,10 @@ std::shared_ptr VirtualThread::CreateMapItem(const std::string &filename if (!OHOS::HiviewDFX::DfxMaps::IsLegalMapItem(filename)) { return nullptr; // skip some memmap } + if (!IsRoot()) { + DeleteRepeatMaps(begin, begin + len, filename); + } + std::shared_ptr map = memMaps_.emplace_back(std::make_shared(begin, begin + len, offset, prot, filename)); memMapsIndexs_.emplace_back(memMaps_.size() >= 1 ? memMaps_.size() - 1 : 0); diff --git a/test/unittest/common/native/virtual_runtime_test.cpp b/test/unittest/common/native/virtual_runtime_test.cpp index 691e1b8671307e48b6678aef353e295c9ed6dd5f..10c51a2038c3d6ca8c9d2059adda32d65b32049e 100644 --- a/test/unittest/common/native/virtual_runtime_test.cpp +++ b/test/unittest/common/native/virtual_runtime_test.cpp @@ -434,6 +434,19 @@ HWTEST_F(VirtualRuntimeTest, UpdateHapSymbolsWithNull, TestSize.Level2) { EXPECT_FALSE(runtime_->UpdateHapSymbols(nullptr)); } + +HWTEST_F(VirtualRuntimeTest, UpdateMapsByRecord, TestSize.Level1) +{ + VirtualThread &thread = runtime_->GetThread(1, 1); + thread.hasRepeat_ = false; + auto& maps = thread.GetMaps(); + size_t size = maps.size(); + PerfRecordMmap recordMmap(false, 1, 1, 10, 10, 0, "0.so"); + PerfRecordMmap2 recordMmap2(false, 1, 1, 30, 10, 0, 0, 0, 0, 0, 0, "1.so"); + runtime_->UpdateMapsByRecord(recordMmap); + runtime_->UpdateMapsByRecord(recordMmap2); + EXPECT_EQ(thread.GetMaps().size(), size); +} } // namespace HiPerf } // namespace Developtools } // namespace OHOS diff --git a/test/unittest/common/native/virtual_thread_test.cpp b/test/unittest/common/native/virtual_thread_test.cpp index 359442967063522442a583fbc68a5df9be5bdbea..e2f2cc20ef493f86b91ab35012ad1adee0223d00 100644 --- a/test/unittest/common/native/virtual_thread_test.cpp +++ b/test/unittest/common/native/virtual_thread_test.cpp @@ -409,6 +409,23 @@ HWTEST_F(VirtualThreadTest, ReadRoMemory, TestSize.Level2) thread.ParseDevhostMap(getpid()); } } + +HWTEST_F(VirtualThreadTest, DeleteRepeatMaps, TestSize.Level1) +{ + std::vector> files; + VirtualThread thread(getpid(), files); + auto& maps = thread.GetMaps(); + + thread.CreateMapItem("0.so", 1000, 2000, 3000); + EXPECT_EQ(maps.size(), 1u); + thread.CreateMapItem("1.so", 3000, 4000, 5000); + EXPECT_EQ(maps.size(), 2u); + thread.DeleteRepeatMaps(2000, 6000, "2.so"); + EXPECT_EQ(maps.size(), 0u); + thread.CreateMapItem("2.so", 2000, 4000, 5000); + thread.ClearMaps(); + EXPECT_EQ(maps.size(), 0u); +} } // namespace HiPerf } // namespace Developtools } // namespace OHOS