diff options
author | Milian Wolff <milian.wolff@kdab.com> | 2017-02-28 23:25:37 +0100 |
---|---|---|
committer | Milian Wolff <milian.wolff@kdab.com> | 2017-03-21 14:48:34 +0000 |
commit | eea91238f58075ec6e991f874be3f057664ba147 (patch) | |
tree | 3639bd5297c608e4f660f8b123df40f3ef7d7a67 | |
parent | 2f1f3e46942b6bdd2c69e3057de19118cc6f3bb7 (diff) |
Refactor PerfElfMap to make it easier to change its internals
Instead of leaking the implementation details such as the QMap
iterators in the API, always return an ElfInfo struct. This
requires us to add the address to the ElfInfo, essentially duplicating
the data that is already used for the QMap key. But this only
marginally increases memory consumption, and does not decrease
performance significantly. Also, future commits to improve the
performance will probably require this anyways.
The code in the symbol table that so far relied on accessing the
mapping internals directly via the iterators is moved into the elfmap
directly. This also allows us to test this part of the code, and
enables us to hide the internals. One exception is the iteration
over all elf infos, which is required to guess the target
architecture. This is still possible, but now uses a simpler foreach
loop over all elf infos, which also makes it possible to change the
underlying data type seamlessly in the future.
To simplify the testing process, ElfInfo also gets a proper
QDebug streaming operator as well as a QTest::toString overload.
The test is updated accordingly, to leverage this new API.
Furthermore, the testing code is simplified by removing the
boolean found parameter in the ElfInfo ctor. Instead, it is now
initialized by calling `file.isFile()` internally.
To show that the performance impact of this change is negleglible,
please compare the following benchmark results to those of the
previous two commits:
PASS : TestElfMap::benchRegisterElfDisjunct(10)
RESULT : TestElfMap::benchRegisterElfDisjunct():"10":
0.0017 msecs per iteration (total: 58, iterations: 32768)
PASS : TestElfMap::benchRegisterElfDisjunct(100)
RESULT : TestElfMap::benchRegisterElfDisjunct():"100":
0.037 msecs per iteration (total: 77, iterations: 2048)
PASS : TestElfMap::benchRegisterElfDisjunct(1000)
RESULT : TestElfMap::benchRegisterElfDisjunct():"1000":
3.8 msecs per iteration (total: 61, iterations: 16)
PASS : TestElfMap::benchRegisterElfDisjunct(2000)
RESULT : TestElfMap::benchRegisterElfDisjunct():"2000":
21 msecs per iteration (total: 85, iterations: 4)
PASS : TestElfMap::benchRegisterElfOverlapping(10)
RESULT : TestElfMap::benchRegisterElfOverlapping():"10":
0.0040 msecs per iteration (total: 66, iterations: 16384)
PASS : TestElfMap::benchRegisterElfOverlapping(100)
RESULT : TestElfMap::benchRegisterElfOverlapping():"100":
0.086 msecs per iteration (total: 89, iterations: 1024)
PASS : TestElfMap::benchRegisterElfOverlapping(1000)
RESULT : TestElfMap::benchRegisterElfOverlapping():"1000":
9.7 msecs per iteration (total: 78, iterations: 8)
PASS : TestElfMap::benchRegisterElfOverlapping(2000)
RESULT : TestElfMap::benchRegisterElfOverlapping():"2000":
35.2 msecs per iteration (total: 141, iterations: 4)
PASS : TestElfMap::benchRegisterElfExpanding(10)
RESULT : TestElfMap::benchRegisterElfExpanding():"10":
0.0019 msecs per iteration (total: 63, iterations: 32768)
PASS : TestElfMap::benchRegisterElfExpanding(100)
RESULT : TestElfMap::benchRegisterElfExpanding():"100":
0.043 msecs per iteration (total: 90, iterations: 2048)
PASS : TestElfMap::benchRegisterElfExpanding(1000)
RESULT : TestElfMap::benchRegisterElfExpanding():"1000":
4.6 msecs per iteration (total: 74, iterations: 16)
PASS : TestElfMap::benchRegisterElfExpanding(2000)
RESULT : TestElfMap::benchRegisterElfExpanding():"2000":
22 msecs per iteration (total: 91, iterations: 4)
PASS : TestElfMap::benchFindElfDisjunct(10)
RESULT : TestElfMap::benchFindElfDisjunct():"10":
0.0029 msecs per iteration (total: 98, iterations: 32768)
PASS : TestElfMap::benchFindElfDisjunct(100)
RESULT : TestElfMap::benchFindElfDisjunct():"100":
0.031 msecs per iteration (total: 65, iterations: 2048)
PASS : TestElfMap::benchFindElfDisjunct(1000)
RESULT : TestElfMap::benchFindElfDisjunct():"1000":
0.40 msecs per iteration (total: 52, iterations: 128)
PASS : TestElfMap::benchFindElfDisjunct(2000)
RESULT : TestElfMap::benchFindElfDisjunct():"2000":
0.85 msecs per iteration (total: 55, iterations: 64)
PASS : TestElfMap::benchFindElfOverlapping(10)
RESULT : TestElfMap::benchFindElfOverlapping():"10":
0.0032 msecs per iteration (total: 53, iterations: 16384)
PASS : TestElfMap::benchFindElfOverlapping(100)
RESULT : TestElfMap::benchFindElfOverlapping():"100":
0.041 msecs per iteration (total: 85, iterations: 2048)
PASS : TestElfMap::benchFindElfOverlapping(1000)
RESULT : TestElfMap::benchFindElfOverlapping():"1000":
0.48 msecs per iteration (total: 62, iterations: 128)
PASS : TestElfMap::benchFindElfOverlapping(2000)
RESULT : TestElfMap::benchFindElfOverlapping():"2000":
1.0 msecs per iteration (total: 65, iterations: 64)
PASS : TestElfMap::benchFindElfExpanding(10)
RESULT : TestElfMap::benchFindElfExpanding():"10":
0.0060 msecs per iteration (total: 99, iterations: 16384)
PASS : TestElfMap::benchFindElfExpanding(100)
RESULT : TestElfMap::benchFindElfExpanding():"100":
0.67 msecs per iteration (total: 87, iterations: 128)
PASS : TestElfMap::benchFindElfExpanding(1000)
RESULT : TestElfMap::benchFindElfExpanding():"1000":
120 msecs per iteration (total: 120, iterations: 1)
PASS : TestElfMap::benchFindElfExpanding(2000)
RESULT : TestElfMap::benchFindElfExpanding():"2000":
696 msecs per iteration (total: 696, iterations: 1)
Change-Id: Id48eb38cc8615b6fa08e84bc4bb6d342b58290b4
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r-- | app/perfelfmap.cpp | 42 | ||||
-rw-r--r-- | app/perfelfmap.h | 38 | ||||
-rw-r--r-- | app/perfsymboltable.cpp | 61 | ||||
-rw-r--r-- | app/perfsymboltable.h | 4 | ||||
-rw-r--r-- | tests/auto/elfmap/tst_elfmap.cpp | 183 |
5 files changed, 192 insertions, 136 deletions
diff --git a/app/perfelfmap.cpp b/app/perfelfmap.cpp index b10026a..13273dd 100644 --- a/app/perfelfmap.cpp +++ b/app/perfelfmap.cpp @@ -21,6 +21,21 @@ #include "perfelfmap.h" #include "perfdata.h" +#include <QDebug> + +QDebug operator<<(QDebug stream, const PerfElfMap::ElfInfo& info) +{ + stream.nospace() << "ElfInfo{" + << "file=" << info.file.fileName() << ", " + << "found=" << info.found << ", " + << "addr=" << info.addr << ", " + << "len=" << info.length << ", " + << "pgoff=" << info.pgoff << ", " + << "timeAdded=" << info.timeAdded << ", " + << "timeOverwritten=" << info.timeOverwritten << "}"; + return stream.space(); +} + bool PerfElfMap::registerElf(const quint64 addr, const quint64 len, quint64 pgoff, const quint64 time, const QFileInfo &fullPath) { @@ -42,13 +57,13 @@ bool PerfElfMap::registerElf(const quint64 addr, const quint64 len, quint64 pgof // reinsert any fragments of it that remain. if (i.key() < addr) { - fragments.insertMulti(i.key(), ElfInfo(i->file, addr - i.key(), i->pgoff, time, - i->timeOverwritten, i->found)); + fragments.insertMulti(i.key(), ElfInfo(i->file, i.key(), addr - i.key(), i->pgoff, + time, i->timeOverwritten)); } if (iEnd > addrEnd) { - fragments.insertMulti(addrEnd, ElfInfo(i->file, iEnd - addrEnd, + fragments.insertMulti(addrEnd, ElfInfo(i->file, addrEnd, iEnd - addrEnd, i->pgoff + addrEnd - i.key(), time, - i->timeOverwritten, i->found)); + i->timeOverwritten)); } i->timeOverwritten = time; } @@ -79,29 +94,38 @@ bool PerfElfMap::registerElf(const quint64 addr, const quint64 len, quint64 pgof } m_elfs.unite(fragments); - m_elfs.insertMulti(addr, ElfInfo(fullPath, len, pgoff, time, overwritten, isFile)); + m_elfs.insertMulti(addr, ElfInfo(fullPath, addr, len, pgoff, time, overwritten)); return cacheInvalid; } -PerfElfMap::ConstIterator PerfElfMap::findElf(quint64 ip, quint64 timestamp) const +PerfElfMap::ElfInfo PerfElfMap::findElf(quint64 ip, quint64 timestamp) const { QMap<quint64, ElfInfo>::ConstIterator i = m_elfs.upperBound(ip); if (i == m_elfs.constEnd() || i.key() != ip) { if (i != m_elfs.constBegin()) --i; else - return m_elfs.constEnd(); + return {}; } while (true) { if (i->timeAdded <= timestamp && i->timeOverwritten > timestamp) - return (i.key() + i->length > ip) ? i : m_elfs.constEnd(); + return (i.key() + i->length > ip) ? i.value() : ElfInfo(); if (i == m_elfs.constBegin()) - return m_elfs.constEnd(); + return {}; --i; } } +bool PerfElfMap::isAddressInRange(quint64 addr) const +{ + if (m_elfs.isEmpty()) + return false; + + const auto &first = m_elfs.first(); + const auto &last = m_elfs.last(); + return first.addr <= addr && addr < (last.addr + last.length); +} diff --git a/app/perfelfmap.h b/app/perfelfmap.h index 33b0ed5..4991943 100644 --- a/app/perfelfmap.h +++ b/app/perfelfmap.h @@ -28,12 +28,30 @@ class PerfElfMap { public: struct ElfInfo { - ElfInfo(const QFileInfo &file = QFileInfo(), quint64 length = 0, quint64 pgoff = 0, - quint64 timeAdded = 0, - quint64 timeOverwritten = std::numeric_limits<quint64>::max(), bool found = true) : - file(file), length(length), pgoff(pgoff), timeAdded(timeAdded), - timeOverwritten(timeOverwritten), found(found) {} + ElfInfo(const QFileInfo &file = QFileInfo(), quint64 addr = 0, quint64 length = 0, + quint64 pgoff = 0, quint64 timeAdded = 0, + quint64 timeOverwritten = std::numeric_limits<quint64>::max()) : + file(file), addr(addr), length(length), pgoff(pgoff), timeAdded(timeAdded), + timeOverwritten(timeOverwritten), found(file.isFile()) {} + + bool isValid() const + { + return length > 0; + } + + bool operator==(const ElfInfo& rhs) const + { + return found == rhs.found + && (!found || file == rhs.file) + && addr == rhs.addr + && length == rhs.length + && pgoff == rhs.pgoff + && timeAdded == rhs.timeAdded + && timeOverwritten == rhs.timeOverwritten; + } + QFileInfo file; + quint64 addr; quint64 length; quint64 pgoff; quint64 timeAdded; @@ -46,25 +64,29 @@ public: bool registerElf(quint64 addr, quint64 len, quint64 pgoff, quint64 time, const QFileInfo &fullPath); - ConstIterator findElf(quint64 ip, quint64 timestamp) const; + ElfInfo findElf(quint64 ip, quint64 timestamp) const; bool isEmpty() const { return m_elfs.isEmpty(); } - ConstIterator constBegin() const + ConstIterator begin() const { return m_elfs.constBegin(); } - ConstIterator constEnd() const + ConstIterator end() const { return m_elfs.constEnd(); } + bool isAddressInRange(quint64 addr) const; + private: QMultiMap<quint64, ElfInfo> m_elfs; // needs to be sorted }; +QDebug operator<<(QDebug stream, const PerfElfMap::ElfInfo& info); + #endif diff --git a/app/perfsymboltable.cpp b/app/perfsymboltable.cpp index b54ff76..48d6613 100644 --- a/app/perfsymboltable.cpp +++ b/app/perfsymboltable.cpp @@ -339,38 +339,38 @@ void PerfSymbolTable::parseDwarf(Dwarf_Die *cudie, Dwarf_Addr bias, qint32 binar } } -static void reportError(PerfElfMap::ConstIterator i, const char *message) +static void reportError(const PerfElfMap::ElfInfo& info, const char *message) { - qWarning() << "failed to report" << i.value().file.absoluteFilePath() << "for" - << hex << i.key() << dec << ":" << message; + qWarning() << "failed to report" << info.file.absoluteFilePath() << "for" + << hex << info.addr << dec << ":" << message; } -Dwfl_Module *PerfSymbolTable::reportElf(PerfElfMap::ConstIterator i) +Dwfl_Module *PerfSymbolTable::reportElf(const PerfElfMap::ElfInfo& info) { - if (i == m_elfs.constEnd() || !i.value().found) + if (!info.isValid() || !info.found) return nullptr; - if (i.value().pgoff > 0) { - reportError(i, "Cannot report file fragments"); + if (info.pgoff > 0) { + reportError(info, "Cannot report file fragments"); return nullptr; } Dwfl_Module *ret = dwfl_report_elf( - m_dwfl, i.value().file.fileName().toLocal8Bit().constData(), - i.value().file.absoluteFilePath().toLocal8Bit().constData(), -1, i.key(), + m_dwfl, info.file.fileName().toLocal8Bit().constData(), + info.file.absoluteFilePath().toLocal8Bit().constData(), -1, info.addr, false); if (!ret) - reportError(i, dwfl_errmsg(dwfl_errno())); + reportError(info, dwfl_errmsg(dwfl_errno())); - if (m_lastMmapAddedTime < i->timeAdded) - m_lastMmapAddedTime = i->timeAdded; - if (m_nextMmapOverwrittenTime > i->timeOverwritten) - m_nextMmapOverwrittenTime = i->timeOverwritten; + if (m_lastMmapAddedTime < info.timeAdded) + m_lastMmapAddedTime = info.timeAdded; + if (m_nextMmapOverwrittenTime > info.timeOverwritten) + m_nextMmapOverwrittenTime = info.timeOverwritten; return ret; } -PerfElfMap::ConstIterator PerfSymbolTable::findElf(quint64 ip, quint64 timestamp) const +PerfElfMap::ElfInfo PerfSymbolTable::findElf(quint64 ip, quint64 timestamp) const { return m_elfs.findElf(ip, timestamp); } @@ -392,12 +392,12 @@ int PerfSymbolTable::lookupFrame(Dwarf_Addr ip, quint64 timestamp, bool isKernel quint64 elfStart = 0; - auto elfIt = findElf(ip, timestamp); - if (elfIt != m_elfs.constEnd()) { - binaryId = m_unwind->resolveString(elfIt.value().file.fileName().toLocal8Bit()); - elfStart = elfIt.key(); + const auto& elf = findElf(ip, timestamp); + if (elf.isValid()) { + binaryId = m_unwind->resolveString(elf.file.fileName().toLocal8Bit()); + elfStart = elf.addr; if (m_dwfl && !mod) - mod = reportElf(elfIt); + mod = reportElf(elf); } PerfUnwind::Location addressLocation( @@ -539,12 +539,7 @@ void PerfSymbolTable::updatePerfMap() bool PerfSymbolTable::containsAddress(quint64 address) const { - if (m_elfs.isEmpty()) - return false; - - const auto last = (--m_elfs.constEnd()); - const auto first = m_elfs.constBegin(); - return first.key() <= address && last.key() + last.value().length > address; + return m_elfs.isAddressInRange(address); } Dwfl *PerfSymbolTable::attachDwfl(quint64 timestamp, void *arg) @@ -555,14 +550,14 @@ Dwfl *PerfSymbolTable::attachDwfl(quint64 timestamp, void *arg) return m_dwfl; // Already attached, nothing to do // Report some random elf, so that dwfl guesses the target architecture. - for (auto it = m_elfs.constBegin(), end = m_elfs.constEnd(); it != end; ++it) { - if (!it->found || it->timeAdded > timestamp || it->timeOverwritten <= timestamp) + for (const auto &elf : m_elfs) { + if (!elf.found || elf.timeAdded > timestamp || elf.timeOverwritten <= timestamp) continue; - if (dwfl_report_elf(m_dwfl, it.value().file.fileName().toLocal8Bit().constData(), - it.value().file.absoluteFilePath().toLocal8Bit().constData(), -1, - it.key(), false)) { - m_lastMmapAddedTime = it->timeAdded; - m_nextMmapOverwrittenTime = it->timeOverwritten; + if (dwfl_report_elf(m_dwfl, elf.file.fileName().toLocal8Bit().constData(), + elf.file.absoluteFilePath().toLocal8Bit().constData(), -1, + elf.addr, false)) { + m_lastMmapAddedTime = elf.timeAdded; + m_nextMmapOverwrittenTime = elf.timeOverwritten; break; } } diff --git a/app/perfsymboltable.h b/app/perfsymboltable.h index 3f12f31..c60852e 100644 --- a/app/perfsymboltable.h +++ b/app/perfsymboltable.h @@ -56,11 +56,11 @@ public: void registerElf(const PerfRecordMmap &mmap, const QString &appPath, const QString &systemRoot, const QString &extraLibsPath); - PerfElfMap::ConstIterator findElf(quint64 ip, quint64 timestamp) const; + PerfElfMap::ElfInfo findElf(quint64 ip, quint64 timestamp) const; // Report an mmap to dwfl and parse it for symbols and inlines, or simply return it if dwfl has // it already - Dwfl_Module *reportElf(PerfElfMap::ConstIterator i); + Dwfl_Module *reportElf(const PerfElfMap::ElfInfo& elf); // Look up a frame and all its inline parents and append them to the given vector. // If the frame hits an elf that hasn't been reported, yet, report it. diff --git a/tests/auto/elfmap/tst_elfmap.cpp b/tests/auto/elfmap/tst_elfmap.cpp index f92b303..68e0c5a 100644 --- a/tests/auto/elfmap/tst_elfmap.cpp +++ b/tests/auto/elfmap/tst_elfmap.cpp @@ -24,49 +24,69 @@ #include "perfelfmap.h" +namespace { +bool registerElf(PerfElfMap *map, const PerfElfMap::ElfInfo &info) +{ + return map->registerElf(info.addr, info.length, info.pgoff, info.timeAdded, + info.file); +} +} + +namespace QTest { +template<> +char *toString(const PerfElfMap::ElfInfo &info) +{ + QString string; + QDebug stream(&string); + stream << info; + return qstrdup(qPrintable(string)); +} +} + class TestElfMap : public QObject { Q_OBJECT private slots: void testNoOverlap() { + const PerfElfMap::ElfInfo invalid; + PerfElfMap map; QVERIFY(map.isEmpty()); - QVERIFY(!map.registerElf(100, 10, 0, 0, {})); + const PerfElfMap::ElfInfo first({}, 100, 10, 0, 0); + + QVERIFY(!registerElf(&map, first)); QVERIFY(!map.isEmpty()); - QCOMPARE(map.constBegin().key(), 100ull); - QCOMPARE(map.constBegin()->length, 10ull); - QCOMPARE(map.constBegin()->timeAdded, 0ull); - - QCOMPARE(map.findElf(99, 0), map.constEnd()); - QCOMPARE(map.findElf(100, 0), map.constBegin()); - QCOMPARE(map.findElf(109, 0), map.constBegin()); - QCOMPARE(map.findElf(110, 0), map.constEnd()); - QCOMPARE(map.findElf(105, 1), map.constBegin()); - - QVERIFY(!map.registerElf(0, 10, 0, 1, {})); - - QCOMPARE(map.constBegin().key(), 0ull); - QCOMPARE(map.constBegin()->length, 10ull); - QCOMPARE(map.constBegin()->timeAdded, 1ull); - - auto first = map.constBegin(); - auto second = first + 1; - - QCOMPARE(map.findElf(0, 0), map.constEnd()); - QCOMPARE(map.findElf(0, 1), first); - QCOMPARE(map.findElf(5, 1), first); - QCOMPARE(map.findElf(9, 1), first); - QCOMPARE(map.findElf(10, 0), map.constEnd()); - QCOMPARE(map.findElf(5, 2), first); - - QCOMPARE(map.findElf(99, 0), map.constEnd()); - QCOMPARE(map.findElf(100, 0), second); - QCOMPARE(map.findElf(109, 0), second); - QCOMPARE(map.findElf(110, 0), map.constEnd()); - QCOMPARE(map.findElf(105, 1), second); + QCOMPARE(std::distance(map.begin(), map.end()), 1); + QCOMPARE(*map.begin(), first); + + QCOMPARE(map.findElf(99, 0), invalid); + QCOMPARE(map.findElf(100, 0), first); + QCOMPARE(map.findElf(109, 0), first); + QCOMPARE(map.findElf(110, 0), invalid); + QCOMPARE(map.findElf(105, 1), first); + + const PerfElfMap::ElfInfo second({}, 0, 10, 0, 1); + QVERIFY(!registerElf(&map, second)); + + QCOMPARE(std::distance(map.begin(), map.end()), 2); + QCOMPARE(*map.begin(), second); + QCOMPARE(*(map.begin()+1), first); + + QCOMPARE(map.findElf(0, 0), invalid); + QCOMPARE(map.findElf(0, 1), second); + QCOMPARE(map.findElf(5, 1), second); + QCOMPARE(map.findElf(9, 1), second); + QCOMPARE(map.findElf(10, 0), invalid); + QCOMPARE(map.findElf(5, 2), second); + + QCOMPARE(map.findElf(99, 0), invalid); + QCOMPARE(map.findElf(100, 0), first); + QCOMPARE(map.findElf(109, 0), first); + QCOMPARE(map.findElf(110, 0), invalid); + QCOMPARE(map.findElf(105, 1), first); } void testOverwrite() @@ -89,66 +109,36 @@ private slots: QFileInfo file2(tmpFile2.fileName()); QCOMPARE(file2.isFile(), secondIsFile); + const PerfElfMap::ElfInfo first(file1, 95, 20, 0, 0, 1); + const PerfElfMap::ElfInfo second(file1, 105, 20, 0, 1, 2); + const PerfElfMap::ElfInfo third(file2, 100, 20, 0, 2); + PerfElfMap map; if (!reversed) { - QVERIFY(!map.registerElf(95, 20, 0, 0, file1)); - QCOMPARE(map.registerElf(105, 20, 0, 1, file1), firstIsFile); - QCOMPARE(map.registerElf(100, 20, 0, 2, file2), firstIsFile || secondIsFile); + QCOMPARE(registerElf(&map, first), false); + QCOMPARE(registerElf(&map, second), firstIsFile); + QCOMPARE(registerElf(&map, third), firstIsFile || secondIsFile); } else { - QVERIFY(!map.registerElf(100, 20, 0, 2, file2)); - QCOMPARE(map.registerElf(105, 20, 0, 1, file1), firstIsFile || secondIsFile); - QCOMPARE(map.registerElf(95, 20, 0, 0, file1), firstIsFile || secondIsFile); + QCOMPARE(registerElf(&map, third), false); + QCOMPARE(registerElf(&map, second), firstIsFile || secondIsFile); + QCOMPARE(registerElf(&map, first), firstIsFile || secondIsFile); } - auto first = map.findElf(110, 0); - QCOMPARE(first.key(), 95ull); - QCOMPARE(first->length, 20ull); - QCOMPARE(first->pgoff, 0ull); - QCOMPARE(first->timeAdded, 0ull); - QCOMPARE(first->timeOverwritten, 1ull); - QCOMPARE(first->file, file1); - - auto second = map.findElf(110, 1); - QCOMPARE(second.key(), 105ull); - QCOMPARE(second->length, 20ull); - QCOMPARE(second->pgoff, 0ull); - QCOMPARE(second->timeAdded, 1ull); - QCOMPARE(second->timeOverwritten, 2ull); - QCOMPARE(second->file, file1); - - auto third = map.findElf(110, 2); - QCOMPARE(third.key(), 100ull); - QCOMPARE(third->length, 20ull); - QCOMPARE(third->pgoff, 0ull); - QCOMPARE(third->timeAdded, 2ull); - QCOMPARE(third->timeOverwritten, std::numeric_limits<quint64>::max()); - QCOMPARE(third->file, file2); + QCOMPARE(map.findElf(110, 0), first); + + QCOMPARE(map.findElf(110, 1), second); + QCOMPARE(map.findElf(110, 2), third); QCOMPARE(map.findElf(110, 3), third); - auto fragment1 = map.findElf(97, 1); - QCOMPARE(fragment1.key(), 95ull); - QCOMPARE(fragment1->length, 10ull); - QCOMPARE(fragment1->pgoff, 0ull); - QCOMPARE(fragment1->timeAdded, 1ull); - QCOMPARE(fragment1->timeOverwritten, 2ull); - QCOMPARE(fragment1->file, file1); - - auto fragment2 = map.findElf(122, 2); - QCOMPARE(fragment2.key(), 120ull); - QCOMPARE(fragment2->length, 5ull); - QCOMPARE(fragment2->pgoff, 15ull); - QCOMPARE(fragment2->timeAdded, 2ull); - QCOMPARE(fragment2->timeOverwritten, std::numeric_limits<quint64>::max()); - QCOMPARE(fragment2->file, file1); - - auto fragment3 = map.findElf(97, 2); - QCOMPARE(fragment3.key(), 95ull); - QCOMPARE(fragment3->length, 5ull); - QCOMPARE(fragment3->pgoff, 0ull); - QCOMPARE(fragment3->timeAdded, 2ull); - QCOMPARE(fragment3->timeOverwritten, std::numeric_limits<quint64>::max()); - QCOMPARE(fragment3->file, file1); + const PerfElfMap::ElfInfo fragment1(file1, 95, 10, 0, 1, 2); + QCOMPARE(map.findElf(97, 1), fragment1); + + const PerfElfMap::ElfInfo fragment2(file1, 120, 5, 15, 2); + QCOMPARE(map.findElf(122, 2), fragment2); + + const PerfElfMap::ElfInfo fragment3(file1, 95, 5, 0, 2); + QCOMPARE(map.findElf(97, 2), fragment3); } void testOverwrite_data() @@ -170,6 +160,31 @@ private slots: QTest::newRow("reversed-no-files") << true << false << false; } + void testIsAddressInRange() + { + PerfElfMap map; + QVERIFY(!map.isAddressInRange(10)); + + const PerfElfMap::ElfInfo first({}, 10, 10, 0, 0); + QVERIFY(!registerElf(&map, first)); + QVERIFY(!map.isAddressInRange(9)); + QVERIFY(map.isAddressInRange(10)); + QVERIFY(map.isAddressInRange(19)); + QVERIFY(!map.isAddressInRange(20)); + + const PerfElfMap::ElfInfo second({}, 30, 10, 0, 1); + QVERIFY(!registerElf(&map, second)); + QVERIFY(!map.isAddressInRange(9)); + QVERIFY(map.isAddressInRange(10)); + QVERIFY(map.isAddressInRange(19)); + QVERIFY(map.isAddressInRange(30)); + QVERIFY(map.isAddressInRange(39)); + QVERIFY(!map.isAddressInRange(40)); + // gaps are also within range + QVERIFY(map.isAddressInRange(20)); + QVERIFY(map.isAddressInRange(29)); + } + void benchRegisterElfDisjunct() { QFETCH(int, numElfMaps); |