diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2018-10-18 15:19:05 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2018-10-22 10:19:04 +0000 |
commit | 573f54d94c7f476d9604e037a7763cab627662a6 (patch) | |
tree | c0b72ae0769db398bcda2b81741f073935219719 | |
parent | 22873e2f8cd1ce128c2a9022fae7616be20a08e5 (diff) |
Don't split mmaps that cover the same region with the same contents
If we get an mmap event for an address range that is already partially
contained in the virtual memory map and contains the same data, we
should not split up the existing mapping, but rather extend it to cover
both the new and old address ranges.
Task-number: QTCREATORBUG-21260
Change-Id: I537f355b82dc31a3408b151d116ba4cab3691ac2
Reviewed-by: Milian Wolff <milian.wolff@kdab.com>
-rw-r--r-- | app/perfelfmap.cpp | 26 | ||||
-rw-r--r-- | tests/auto/elfmap/tst_elfmap.cpp | 35 |
2 files changed, 58 insertions, 3 deletions
diff --git a/app/perfelfmap.cpp b/app/perfelfmap.cpp index 8d2f46e..d5cf084 100644 --- a/app/perfelfmap.cpp +++ b/app/perfelfmap.cpp @@ -52,21 +52,41 @@ struct SortByAddr }; } -bool PerfElfMap::registerElf(const quint64 addr, const quint64 len, quint64 pgoff, +bool PerfElfMap::registerElf(quint64 addr, quint64 len, quint64 pgoff, const QFileInfo &fullPath, const QByteArray &originalFileName, const QByteArray &originalPath) { bool cacheInvalid = false; - const quint64 addrEnd = addr + len; + quint64 addrEnd = addr + len; const bool isFile = fullPath.isFile(); QVarLengthArray<ElfInfo, 8> newElfs; QVarLengthArray<int, 8> removedElfs; for (auto i = m_elfs.begin(), end = m_elfs.end(); i != end && i->addr < addrEnd; ++i) { const quint64 iEnd = i->addr + i->length; - if (iEnd <= addr) + if (iEnd < addr) continue; + if (addr - pgoff == i->addr - i->pgoff && originalPath == i->originalPath) { + // Remapping parts of the same file in the same place: Extend to maximum continuous + // address range and check if we already have that. + addr = qMin(addr, i->addr); + pgoff = qMin(pgoff, i->pgoff); + addrEnd = qMax(addrEnd, iEnd); + len = addrEnd - addr; + if (addr == i->addr && len == i->length) { + // New mapping is fully contained in old one: Nothing to do. + Q_ASSERT(!cacheInvalid); + Q_ASSERT(newElfs.isEmpty()); + Q_ASSERT(removedElfs.isEmpty()); + return false; + } + } else if (iEnd == addr) { + // Directly adjacent sections of the same file can be merged. Ones of different files + // don't bother each other. + continue; + } + // Newly added elf overwrites existing one. Mark the existing one as overwritten and // reinsert any fragments of it that remain. diff --git a/tests/auto/elfmap/tst_elfmap.cpp b/tests/auto/elfmap/tst_elfmap.cpp index aac377b..f645577 100644 --- a/tests/auto/elfmap/tst_elfmap.cpp +++ b/tests/auto/elfmap/tst_elfmap.cpp @@ -167,6 +167,41 @@ private slots: QVERIFY(map.isAddressInRange(29)); } + void testExtendMapping() + { + PerfElfMap map; + const PerfElfMap::ElfInfo first({}, 0, 5000, 0, "lalala.so", "/tmp/lalala.so"); + registerElf(&map, first); + QCOMPARE(map.findElf(100), first); + + // fully contained in the first mapping + const PerfElfMap::ElfInfo second({}, 20, 500, 20, "lalala.so", "/tmp/lalala.so"); + registerElf(&map, second); + QCOMPARE(map.findElf(100), first); + + // extend the first mapping + const PerfElfMap::ElfInfo third({}, 2000, 8000, 2000, "lalala.so", "/tmp/lalala.so"); + registerElf(&map, third); + const PerfElfMap::ElfInfo extended({}, 0, 10000, 0, "lalala.so", "/tmp/lalala.so"); + QCOMPARE(map.findElf(100), extended); + QCOMPARE(map.findElf(2200), extended); + + // this has a gap, so don't extend directly + const PerfElfMap::ElfInfo fourth({}, 12000, 100, 100, "lalala.so", "/tmp/lalala.so"); + registerElf(&map, fourth); + QCOMPARE(map.findElf(12000), fourth); + + const PerfElfMap::ElfInfo fifth({}, 2000, 500, 3000, "lalala.so", "/tmp/lalala.so"); + registerElf(&map, fifth); + QCOMPARE(map.findElf(2200), fifth); + + const PerfElfMap::ElfInfo remainder1({}, 0, 2000, 0, "lalala.so", "/tmp/lalala.so"); + QCOMPARE(map.findElf(100), remainder1); + + const PerfElfMap::ElfInfo remainder2({}, 2500, 7500, 2500, "lalala.so", "/tmp/lalala.so"); + QCOMPARE(map.findElf(3000), remainder2); + } + void benchRegisterElfDisjunct() { QFETCH(uint, numElfMaps); |