summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2018-10-18 15:19:05 +0200
committerUlf Hermann <ulf.hermann@qt.io>2018-10-22 10:19:04 +0000
commit573f54d94c7f476d9604e037a7763cab627662a6 (patch)
treec0b72ae0769db398bcda2b81741f073935219719
parent22873e2f8cd1ce128c2a9022fae7616be20a08e5 (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.cpp26
-rw-r--r--tests/auto/elfmap/tst_elfmap.cpp35
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);